UNPKG

@near-lake/primitives

Version:

Near Protocol primitive datatypes utilized by near-lake-framework and QueryAPI

231 lines (230 loc) 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockHeader = exports.Block = void 0; const receipts_1 = require("./receipts"); const events_1 = require("./events"); const stateChanges_1 = require("./stateChanges"); const helpers_1 = require("../helpers"); const functionCallView_1 = require("./functionCallView"); /** * The `Block` type is used to represent a block in the NEAR Lake Framework. * * **Important Notes on `Block`:** * - All the entities located on different shards were merged into one single list without differentiation. * - `Block` is not the fairest name for this structure either. NEAR Protocol is a sharded blockchain, so its block is actually an ephemeral structure that represents a collection of real blocks called chunks in NEAR Protocol. */ class Block { constructor( /** * Low-level structure for backward compatibility. * As implemented in previous versions of [`near-lake-framework`](https://www.npmjs.com/package/near-lake-framework). */ streamerMessage, executedReceipts, /** * Receipts included on the chain but not executed yet marked as “postponed”: they are represented by the same structure `Receipt` (see the corresponding section in this doc for more details). */ postponedReceipts, /** * List of included `Transactions`, converted into `Receipts`. * * **_NOTE_:** Heads up! You might want to know about `Transactions` to know where the action chain has begun. Unlike Ethereum, where a Transaction contains everything you may want to know about a particular interaction on the Ethereum blockchain, Near Protocol because of its asynchronous nature converts a `Transaction` into a `Receipt` before executing it. Thus, On NEAR, `Receipts` are more important for figuring out what happened on-chain as a result of a Transaction signed by a user. Read more about [Transactions on Near](https://nomicon.io/RuntimeSpec/Transactions) here. * */ transactions, _actions, _events, _stateChanges) { this.streamerMessage = streamerMessage; this.executedReceipts = executedReceipts; this.postponedReceipts = postponedReceipts; this.transactions = transactions; this._actions = _actions; this._events = _events; this._stateChanges = _stateChanges; } /** * Returns the block hash. A shortcut to get the data from the block header. */ get blockHash() { return this.header().hash; } /** * Returns the previous block hash. A shortcut to get the data from the block header. */ get prevBlockHash() { return this.header().prevHash; } /** * Returns the block height. A shortcut to get the data from the block header. */ get blockHeight() { return this.header().height; } /** * Returns the block date in ISO format, e.g. 2022-01-01. */ get blockDate() { return new Date(this.streamerMessage.block.header.timestamp / 1000000) .toISOString() .substring(0, 10); } /** * Returns a `BlockHeader` structure of the block * See `BlockHeader` structure sections for details. */ header() { return BlockHeader.fromStreamerMessage(this.streamerMessage); } /** * Returns a slice of `Receipts` executed in the block. * Basically is a getter for the `executedReceipts` field. */ receipts() { if (this.executedReceipts.length == 0) { this.executedReceipts = this.streamerMessage.shards .flatMap((shard) => shard.receiptExecutionOutcomes) .map((executionReceipt) => receipts_1.Receipt.fromOutcomeWithReceipt(executionReceipt)); } return this.executedReceipts; } /** * Returns an Array of `Actions` executed in the block. */ actions() { return this.streamerMessage.shards .flatMap((shard) => shard.receiptExecutionOutcomes) .filter((executionOutcomeWithReceipt) => receipts_1.Action.isActionReceipt(executionOutcomeWithReceipt.receipt)) .map((executionOutcomeWithReceipt) => receipts_1.Action.fromOutcomeWithReceipt(executionOutcomeWithReceipt)) .filter((action) => action !== null); } /** * Returns an Array of function calls executed in the block matching provided filters. * @param receiverFilter - filter by contract name (e.g. `*.pool.near,*.poolv1.near`). Default is `*` (all contracts). * @param statusFilter - filter by receipt status (all|onlySuccessful|onlyFailed). Default is `onlySuccessful`. */ functionCalls(receiverFilter = "*", statusFilter = "onlySuccessful") { return this.actions() .filter((action) => (0, helpers_1.isMatchingReceiver)(action.receiverId, receiverFilter) && (0, helpers_1.isMatchingReceiptStatus)(action.receiptStatus, statusFilter)) .flatMap((a) => a.operations .filter((op) => op.hasOwnProperty("FunctionCall")) .map((op) => functionCallView_1.FunctionCallView.fromFunctionCall(Object(op).FunctionCall, a))); } /** * Returns an Array of function calls to receivers matching receiverFilter. * @param receiverFilter - filter by contract name (e.g. `*.pool.near,*.poolv1.near`). Default is `*` (all contracts). * @param method - name of the method to filter by. Returns all function calls to receiverFilter if not provided. * @param statusFilter - filter by receipt status (all|onlySuccessful|onlyFailed). Default is `onlySuccessful`. */ functionCallsToReceiver(receiverFilter = "*", method, statusFilter = "onlySuccessful") { return this.functionCalls(receiverFilter, statusFilter).filter((call) => method ? call.methodName === method : true); } /** * Returns `Events` emitted in the block. */ events() { const events = this.receipts().flatMap((executedReceipt) => executedReceipt.logs .filter(events_1.RawEvent.isEvent) .map(events_1.RawEvent.fromLog) .map((rawEvent) => { return new events_1.Event(executedReceipt.receiptId, rawEvent); })); return events; } /** * Returns raw logs regardless of the fact that they are standard events or not. */ logs() { const logs = this.receipts().flatMap((executedReceipt) => executedReceipt.logs.map((rawLog) => { let log = { relatedReceiptId: executedReceipt.receiptId, log: rawLog, }; return log; })); return logs; } /** * Returns an Array of `StateChange` occurred in the block. */ stateChanges() { if (this._stateChanges.length == 0) { this._stateChanges = this.streamerMessage.shards .flatMap((shard) => shard.stateChanges) .map(stateChanges_1.StateChange.fromStateChangeView); } return this._stateChanges; } /** * Returns `Action` of the provided `receipt_id` from the block if any. Returns `undefined` if there is no corresponding `Action`. * * This method uses the internal `Block` `action` field which is empty by default and will be filled with the block’s actions on the first call to optimize memory usage. * * The result is either `Action | undefined` since there might be a request for an `Action` by `receipt_id` from another block, in which case this method will be unable to find the `Action` in the current block. In the other case, the request might be for an `Action` for a `receipt_id` that belongs to a `DataReceipt` where an action does not exist. */ actionByReceiptId(receipt_id) { if (this._actions.size == 0) { this.buildActionsHashmap(); } return this._actions.get(receipt_id); } /** * Returns an Array of Events emitted by `ExecutionOutcome` for the given `receipt_id`. There might be more than one `Event` for the `Receipt` or there might be none of them. In the latter case, this method returns an empty Array. */ eventsByReceiptId(receipt_id) { if (this._events.size == 0) { this.buildEventsHashmap(); } return this._events.get(receipt_id) || []; } /** * Returns an Array of Events emitted by `ExecutionOutcome` for the given `account_id`. There might be more than one `Event` for the `Receipt` or there might be none of them. In the latter case, this method returns an empty Array. */ eventsByAccountId(account_id) { return this.events().filter((event) => { const action = this.actionByReceiptId(event.receiptId); return (action === null || action === void 0 ? void 0 : action.receiverId) == account_id || (action === null || action === void 0 ? void 0 : action.signerId) == account_id; }); } buildActionsHashmap() { const actions = new Map(); this.actions().forEach((action) => { actions.set(action.receiptId, action); }); this._actions = actions; } buildEventsHashmap() { const events = new Map(); for (const receipt of this.executedReceipts) { events.set(receipt.receiptId, receipt.events); } return events; } static fromStreamerMessage(streamerMessage) { return new Block(streamerMessage, [], [], [], new Map(), new Map(), []); } } exports.Block = Block; /** * Replacement for `BlockHeaderView` from [near-primitives](https://github.com/near/nearcore/tree/master/core/primitives). Shrunken and simplified. * * **Note:** the original `BlockHeaderView` is still accessible via the `.streamerMessage` attribute. */ class BlockHeader { constructor(height, hash, prevHash, author, timestampNanosec, epochId, nextEpochId, gasPrice, totalSupply, latestProtocolVersion, randomValue, chunksIncluded, validatorProposals) { this.height = height; this.hash = hash; this.prevHash = prevHash; this.author = author; this.timestampNanosec = timestampNanosec; this.epochId = epochId; this.nextEpochId = nextEpochId; this.gasPrice = gasPrice; this.totalSupply = totalSupply; this.latestProtocolVersion = latestProtocolVersion; this.randomValue = randomValue; this.chunksIncluded = chunksIncluded; this.validatorProposals = validatorProposals; } static fromStreamerMessage(streamerMessage) { return new BlockHeader(streamerMessage.block.header.height, streamerMessage.block.header.hash, streamerMessage.block.header.prevHash, streamerMessage.block.author, streamerMessage.block.header.timestampNanosec, streamerMessage.block.header.epochId, streamerMessage.block.header.nextEpochId, streamerMessage.block.header.gasPrice, streamerMessage.block.header.totalSupply, streamerMessage.block.header.latestProtocolVersion, streamerMessage.block.header.randomValue, streamerMessage.block.header.chunksIncluded, streamerMessage.block.header.validatorProposals); } } exports.BlockHeader = BlockHeader;