noob-ethereum
Version:
A simple Ethereum library
148 lines (147 loc) • 6.51 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateBlockTransactionHashes = exports.calculateTransactionHashes = exports.calculateTransactionHash = exports.serialiseTransactions = exports.serialiseTransaction = void 0;
const rlp = __importStar(require("./rlp"));
const keccak_1 = __importDefault(require("keccak"));
const conversion_1 = require("../utils/conversion");
/* ---------------------------- Internal Methods ---------------------------------- */
function convertToByteArray(field) {
const isNested = Array.isArray(field);
const emptyArr = Array.isArray(field) && field.length === 0;
if (emptyArr)
return [];
if (!isNested) {
if (field === '0x0') {
return Uint8Array.from([]);
}
else {
return toByteArr(field);
}
}
else {
return convertToByteArray(field);
}
}
function toByteArr(field) {
const arr = [];
const suffix = field.slice(2);
const byteLength = Math.ceil(suffix.length / 2);
const padded = (0, conversion_1.hexZeroPad)(field, byteLength).slice(2);
for (let i = 0; i < padded.length; i += 2) {
arr.push(parseInt(padded.slice(i, i + 2), 16));
}
return new Uint8Array(arr);
}
/* -------------------------------------------------------------------------------- */
/* ******************************************************************************** */
/* --------------------------- Methods to Expose ---------------------------------- */
/**
* Serialise a transaction via RLP-encoding scheme
* @param {RawTransaction} tx - transaction object (can be legacy, 2930, 1559 type transaction bodies)
* @returns {Buffer} - RLP-encoded transaction
*/
function serialiseTransaction(tx) {
const toByteTuple = (tuple) => {
return tuple.map((field) => convertToByteArray(field));
};
switch (tx.type) {
/* Legacy transaction */
case '0x0':
default: {
const { nonce, gasPrice, gas, to, value, input, v, r, s } = tx;
const tuple = [nonce, gasPrice, gas, to, value, input, v, r, s];
const byteTuple = toByteTuple(tuple);
return Buffer.from(rlp.encode(byteTuple));
}
/* EIP-2930 transaction */
case '0x1': {
const { chainId, nonce, gasPrice, gas, to, value, input, accessList, v, r, s } = tx;
const tuple = [chainId, nonce, gasPrice, gas, to, value, input, accessList, v, r, s];
const byteTuple = toByteTuple(tuple);
const encodedPayload = Buffer.from(rlp.encode(byteTuple));
const type = Buffer.from('01', 'hex');
return Buffer.concat([type, encodedPayload]);
}
/* EIP-1559 transaction */
case '0x2': {
const { chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gas, to, value, input, accessList, v, r, s } = tx;
const tuple = [chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gas, to, value, input, accessList, v, r, s];
const byteTuple = toByteTuple(tuple);
const encodedPayload = Buffer.from(rlp.encode(byteTuple));
const type = Buffer.from('02', 'hex');
return Buffer.concat([type, encodedPayload]);
}
}
}
exports.serialiseTransaction = serialiseTransaction;
/**
* Serialise an array of transaction objects via RLP-encoding scheme
* @param {RawTransactions} arr - array of transaction objects
* @returns {Buffer[]} - array of RLP-encoded transactions
*/
function serialiseTransactions(arr) {
return arr.map((tx) => serialiseTransaction(tx));
}
exports.serialiseTransactions = serialiseTransactions;
/**
* Calculate transaction hash generated by a transaction object
* @param {Raw Transaction} tx - transaction object (can be legacy, 2930, 1559 type transaction bodies)
* @returns {string} - transaction hash computed
*/
function calculateTransactionHash(tx) {
const serialised = serialiseTransaction(tx);
return (0, conversion_1.hexify)((0, keccak_1.default)('keccak256').update(serialised).digest('hex'));
}
exports.calculateTransactionHash = calculateTransactionHash;
/**
* Calculate transaction hashes generated from an array of transactions provided
* @param {RawTransactions} arr - array of transaction objects
* @returns {string[]} - array of transaction hashes computed
*/
function calculateTransactionHashes(arr) {
const hashes = [];
if (typeof arr[0] !== 'string') {
arr.forEach((t) => hashes.push(calculateTransactionHash(t)));
}
return hashes;
}
exports.calculateTransactionHashes = calculateTransactionHashes;
/**
* Given a raw block (with full transaction objects), return the calculated transaction hashes
* @param {IRawBlock} block - raw block including full transaction records
* @returns {string[]} - an array of transaction hash strings
*/
function calculateBlockTransactionHashes(block) {
if (block.transactions[0] === 'string') {
console.error(`Block supplied does not consist of an array of transaction objects corresponding to the 'transactions' key (possibly a condensed block with only transaction hashes)`);
return [];
}
return calculateTransactionHashes(block.transactions);
}
exports.calculateBlockTransactionHashes = calculateBlockTransactionHashes;