noob-ethereum
Version:
A simple Ethereum library
160 lines (159 loc) • 7.04 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 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);
});
});
;