UNPKG

noob-ethereum

Version:
160 lines (159 loc) 7.04 kB
"use strict"; 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 ethereumjs_util_1 = require("ethereumjs-util"); const trie_1 = require("@ethereumjs/trie"); const keccak_1 = __importDefault(require("keccak")); const conversion_1 = require("../../lib/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 ethereumjs_util_1.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 = ethereumjs_util_1.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 = ethereumjs_util_1.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; /* ---------------------------- Local Testing ---------------------------------- */ const _10467135_json_1 = __importDefault(require("../../seeder/blocks/legacy/10467135.json")); const trie = new trie_1.Trie(); const testBlock = _10467135_json_1.default; const serialisedTxs = serialiseTransactions(testBlock.transactions); async function insertTransactions(arr) { for (let i = 0; i < arr.length; i++) { await trie.put(ethereumjs_util_1.rlp.encode(i), arr[i]); if (i === 0) break; } const path = await trie.findPath(ethereumjs_util_1.rlp.encode(0)); const decoded = ethereumjs_util_1.rlp.decode(path.node._value); const hexified = decoded.map((elem) => (0, conversion_1.hexify)(elem)); console.log(path); console.log(decoded); console.log(hexified); } insertTransactions(serialisedTxs).then(() => { const expected = testBlock.transactionsRoot; const calculated = (0, conversion_1.hexify)(trie.root); // console.log(expected, calculated, expected === calculated); trie.get(ethereumjs_util_1.rlp.encode(310)).then((x) => { // console.log(x); const data = ethereumjs_util_1.rlp.decode(x); // console.log(data); // convert tuple fields from buffer to hex strings let hexed = data.map((elem) => (0, conversion_1.hexify)(elem)); // console.log(hexed); }); trie.findPath(ethereumjs_util_1.rlp.encode(0)).then((y) => { console.log(y); }); });