noob-ethereum
Version:
A simple Ethereum library
128 lines (127 loc) • 5.5 kB
JavaScript
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 ethers_1 = require("ethers");
const keccak_1 = __importDefault(require("keccak"));
const conversion_1 = require("../../lib/utils/conversion");
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 = ethers_1.utils.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);
}
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;
function serialiseTransactions(arr) {
return arr.map((tx) => serialiseTransaction(tx));
}
exports.serialiseTransactions = serialiseTransactions;
function calculateTransactionHash(tx) {
const serialised = serialiseTransaction(tx);
return '0x' + (0, keccak_1.default)('keccak256').update(serialised).digest('hex');
}
exports.calculateTransactionHash = calculateTransactionHash;
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;
const _15122054_json_1 = __importDefault(require("../../seeder/blocks/1559/15122054.json"));
const trie = new trie_1.Trie();
const testBlock = _15122054_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]);
}
const expected = testBlock.transactionsRoot;
const calculated = '0x' + trie.root.toString('hex');
console.log(expected, calculated, expected === calculated);
}
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(0)).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);
});
});
;