@ethereumjs/block
Advanced tools
Comparing version 3.0.0-beta.1 to 3.0.0-beta.2
@@ -9,2 +9,11 @@ # Changelog | ||
## 3.0.0-beta.2 - 2020-11-12 | ||
This is the second beta release towards a final library release, see [beta.1 release notes](https://github.com/ethereumjs/ethereumjs-vm/releases/tag/%40ethereumjs%2Ftx%403.0.0-beta.1) for an overview on the full changes since the last publicly released version. | ||
- Added `freeze` option to allow for block freeze deactivation (e.g. to allow for subclassing block and adding additional parameters), see PR [#941](https://github.com/ethereumjs/ethereumjs-vm/pull/941) | ||
- **Breaking:** Difficulty-depending methods `canonicalDifficulty()` and `validateDifficulty()` in block and header now throw on non-PoW chains, see PR [#937](https://github.com/ethereumjs/ethereumjs-vm/pull/937) | ||
- **Breaking:** Non-blockchain dependent validation checks have been extracted from `validate()` to its own `Block.validateData()` function. For the `validate()` method in block and header `blockchain` is now a mandatory parameter, see PR [#942](https://github.com/ethereumjs/ethereumjs-vm/pull/942) | ||
- Fixed bug where block options have not been passed on to the main constructor from the static factory methods, see PR [#941](https://github.com/ethereumjs/ethereumjs-vm/pull/941) | ||
## 3.0.0-beta.1 - 2020-10-22 | ||
@@ -69,3 +78,3 @@ | ||
1. Pass in a Header-attribute named dictionary to `BlockHeader.fromHeaderData(headerData: HeaderData = {}, opts: BlockOptions = {})`: | ||
1. Pass in a Header-attribute named dictionary to `BlockHeader.fromHeaderData(headerData: HeaderData = {}, opts?: BlockOptions)`: | ||
@@ -80,3 +89,3 @@ ```typescript | ||
} | ||
const header = BlockHeader.fromHeaderData(headerData, {}) | ||
const header = BlockHeader.fromHeaderData(headerData) | ||
``` | ||
@@ -89,5 +98,5 @@ | ||
'f901f7a06bfee7294bf44572b7266358e627f3c35105e1c3851f3de09e6d646f955725a7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000f837a120080845d20ab8080a00000000000000000000000000000000000000000000000000000000000000000880000000000000000', | ||
'hex', | ||
'hex' | ||
) | ||
const header = BlockHeader.fromRLPSerializedHeader(serialized, {}) | ||
const header = BlockHeader.fromRLPSerializedHeader(serialized) | ||
``` | ||
@@ -99,3 +108,3 @@ | ||
const valuesArray = header.raw() | ||
BlockHeader.fromValuesArray(valuesArray, {}) | ||
BlockHeader.fromValuesArray(valuesArray) | ||
``` | ||
@@ -110,5 +119,5 @@ | ||
- `Block.fromBlockData(blockData: BlockData = {}, opts: BlockOptions = {})` | ||
- `Block.fromRLPSerializedBlock(serialized: Buffer, opts: BlockOptions = {})` | ||
- `Block.fromValuesArray(values: BlockBuffer, opts: BlockOptions = {})` | ||
- `Block.fromBlockData(blockData: BlockData = {}, opts?: BlockOptions)` | ||
- `Block.fromRLPSerializedBlock(serialized: Buffer, opts?: BlockOptions)` | ||
- `Block.fromValuesArray(values: BlockBuffer, opts?: BlockOptions)` | ||
@@ -152,3 +161,3 @@ Learn more about the full API in the [docs](./docs/README.md). | ||
**Breaking**: The signatures of the following header validation methods have been updated to take a `parentBlockHeader` instead of a | ||
**Breaking**: The signatures of the following header validation methods have been updated to take a `parentBlockHeader` instead of a | ||
`parentBlock` input parameter for consistency and removing a circling dependency with `Block`: | ||
@@ -165,3 +174,3 @@ | ||
**Breaking:** The default HF on the library has been updated from `petersburg` to `instanbul`, see PR [#906](https://github.com/ethereumjs/ethereumjs-vm/pull/906). | ||
**Breaking:** The default HF on the library has been updated from `petersburg` to `istanbul`, see PR [#906](https://github.com/ethereumjs/ethereumjs-vm/pull/906). | ||
The HF setting is now automatically taken from the HF set for `Common.DEAULT_HARDFORK`, | ||
@@ -172,4 +181,4 @@ see PR [#863](https://github.com/ethereumjs/ethereumjs-vm/pull/863). | ||
We significantly updated our internal tool and CI setup along the work on | ||
PR [#913](https://github.com/ethereumjs/ethereumjs-vm/pull/913) with an update to `ESLint` from `TSLint` | ||
We significantly updated our internal tool and CI setup along the work on | ||
PR [#913](https://github.com/ethereumjs/ethereumjs-vm/pull/913) with an update to `ESLint` from `TSLint` | ||
for code linting and formatting and the introduction of a new build setup. | ||
@@ -191,2 +200,3 @@ | ||
PR [#843](https://github.com/ethereumjs/ethereumjs-vm/pull/843) | ||
- Added the `calcDifficultyFromHeader` constructor option. If this `BlockHeader` is supplied, then the `difficulty` of the constructed `BlockHeader` will be set to the canonical difficulty (also if `difficulty` is set as parameter in the constructor). See [#929](https://github.com/ethereumjs/ethereumjs-vm/pull/929) | ||
@@ -193,0 +203,0 @@ **Changes and Refactoring** |
@@ -51,7 +51,8 @@ /// <reference types="node" /> | ||
/** | ||
* Validates the transaction trie. | ||
* Validates the transaction trie by generating a trie | ||
* and do a check on the root hash. | ||
*/ | ||
validateTransactionsTrie(): Promise<boolean>; | ||
/** | ||
* Validates the transactions. | ||
* Validates transaction signatures and minimum gas requirements. | ||
* | ||
@@ -64,8 +65,24 @@ * @param stringError - If `true`, a string with the indices of the invalid txs is returned. | ||
/** | ||
* Validates the block, throwing if invalid. | ||
* Performs the following consistency checks on the block: | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* - Value checks on the header fields | ||
* - Signature and gasLimit validation for included txs | ||
* - Validation of the tx trie | ||
* - Consistency checks and header validation of included uncles | ||
* | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
*/ | ||
validate(blockchain?: Blockchain): Promise<void>; | ||
validate(blockchain: Blockchain): Promise<void>; | ||
/** | ||
* Validates the block data, throwing if invalid. | ||
* This can be checked on the Block itself without needing access to any parent block | ||
* It checks: | ||
* - All transactions are valid | ||
* - The transactions trie is valid | ||
* - The uncle hash is valid | ||
*/ | ||
validateData(): Promise<void>; | ||
/** | ||
* Validates the uncle's hash. | ||
@@ -75,7 +92,10 @@ */ | ||
/** | ||
* Validates the uncles that are in the block, if any. This method throws if they are invalid. | ||
* Consistency checks and header validation for uncles included | ||
* in the block, if any. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - additionally validate against an @ethereumjs/blockchain instance | ||
*/ | ||
validateUncles(blockchain?: Blockchain): Promise<void>; | ||
validateUncles(blockchain: Blockchain): Promise<void>; | ||
/** | ||
@@ -94,3 +114,4 @@ * Returns the canonical difficulty for this block. | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -97,0 +118,0 @@ * @param parentBlock - the parent of this `Block` |
@@ -95,2 +95,3 @@ "use strict"; | ||
if (opts === void 0) { opts = {}; } | ||
var _a; | ||
this.transactions = []; | ||
@@ -103,3 +104,6 @@ this.uncleHeaders = []; | ||
this._common = this.header._common; | ||
Object.freeze(this); | ||
var freeze = (_a = opts === null || opts === void 0 ? void 0 : opts.freeze) !== null && _a !== void 0 ? _a : true; | ||
if (freeze) { | ||
Object.freeze(this); | ||
} | ||
} | ||
@@ -109,3 +113,2 @@ Block.fromBlockData = function (blockData, opts) { | ||
if (blockData === void 0) { blockData = {}; } | ||
if (opts === void 0) { opts = {}; } | ||
var headerData = blockData.header, txsData = blockData.transactions, uhsData = blockData.uncleHeaders; | ||
@@ -145,6 +148,5 @@ var header = header_1.BlockHeader.fromHeaderData(headerData, opts); | ||
} | ||
return new Block(header, transactions, uncleHeaders); | ||
return new Block(header, transactions, uncleHeaders, opts); | ||
}; | ||
Block.fromRLPSerializedBlock = function (serialized, opts) { | ||
if (opts === void 0) { opts = {}; } | ||
var values = ethereumjs_util_1.rlp.decode(serialized); | ||
@@ -158,3 +160,2 @@ if (!Array.isArray(values)) { | ||
var e_3, _a, e_4, _b; | ||
if (opts === void 0) { opts = {}; } | ||
if (values.length > 3) { | ||
@@ -195,3 +196,3 @@ throw new Error('invalid block. More values than expected were received'); | ||
} | ||
return new Block(header, transactions, uncleHeaders); | ||
return new Block(header, transactions, uncleHeaders, opts); | ||
}; | ||
@@ -203,3 +204,2 @@ /** | ||
if (blockData === void 0) { blockData = {}; } | ||
if (opts === void 0) { opts = {}; } | ||
opts = __assign(__assign({}, opts), { initWithGenesisHeader: true }); | ||
@@ -266,3 +266,4 @@ return Block.fromBlockData(blockData, opts); | ||
/** | ||
* Validates the transaction trie. | ||
* Validates the transaction trie by generating a trie | ||
* and do a check on the root hash. | ||
*/ | ||
@@ -299,9 +300,15 @@ Block.prototype.validateTransactionsTrie = function () { | ||
/** | ||
* Validates the block, throwing if invalid. | ||
* Performs the following consistency checks on the block: | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* - Value checks on the header fields | ||
* - Signature and gasLimit validation for included txs | ||
* - Validation of the tx trie | ||
* - Consistency checks and header validation of included uncles | ||
* | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
*/ | ||
Block.prototype.validate = function (blockchain) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var txErrors, validateTxTrie; | ||
return __generator(this, function (_a) { | ||
@@ -312,2 +319,27 @@ switch (_a.label) { | ||
_a.sent(); | ||
return [4 /*yield*/, this.validateUncles(blockchain)]; | ||
case 2: | ||
_a.sent(); | ||
return [4 /*yield*/, this.validateData()]; | ||
case 3: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Validates the block data, throwing if invalid. | ||
* This can be checked on the Block itself without needing access to any parent block | ||
* It checks: | ||
* - All transactions are valid | ||
* - The transactions trie is valid | ||
* - The uncle hash is valid | ||
*/ | ||
Block.prototype.validateData = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var txErrors, validateTxTrie; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
txErrors = this.validateTransactions(true); | ||
@@ -318,3 +350,3 @@ if (txErrors.length > 0) { | ||
return [4 /*yield*/, this.validateTransactionsTrie()]; | ||
case 2: | ||
case 1: | ||
validateTxTrie = _a.sent(); | ||
@@ -324,5 +356,2 @@ if (!validateTxTrie) { | ||
} | ||
return [4 /*yield*/, this.validateUncles(blockchain)]; | ||
case 3: | ||
_a.sent(); | ||
if (!this.validateUnclesHash()) { | ||
@@ -344,5 +373,8 @@ throw new Error('invalid uncle hash'); | ||
/** | ||
* Validates the uncles that are in the block, if any. This method throws if they are invalid. | ||
* Consistency checks and header validation for uncles included | ||
* in the block, if any. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - additionally validate against an @ethereumjs/blockchain instance | ||
*/ | ||
@@ -414,3 +446,4 @@ Block.prototype.validateUncles = function (blockchain) { | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -417,0 +450,0 @@ * @param parentBlock - the parent of this `Block` |
@@ -27,4 +27,4 @@ /// <reference types="node" /> | ||
static fromHeaderData(headerData?: HeaderData, opts?: BlockOptions): BlockHeader; | ||
static fromRLPSerializedHeader(serialized: Buffer, opts: BlockOptions): BlockHeader; | ||
static fromValuesArray(values: BlockHeaderBuffer, opts: BlockOptions): BlockHeader; | ||
static fromRLPSerializedHeader(serialized: Buffer, opts?: BlockOptions): BlockHeader; | ||
static fromValuesArray(values: BlockHeaderBuffer, opts?: BlockOptions): BlockHeader; | ||
/** | ||
@@ -58,3 +58,4 @@ * Alias for Header.fromHeaderData() with initWithGenesisHeader set to true. | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -65,8 +66,13 @@ * @param parentBlockHeader - the header from the parent `Block` of this header | ||
/** | ||
* Validates the block header, throwing if invalid. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Validates the block header, throwing if invalid. It is being validated against the reported `parentHash`. | ||
* It verifies the current block against the `parentHash`: | ||
* - The `parentHash` is part of the blockchain (it is a valid header) | ||
* - Current block number is parent block number + 1 | ||
* - Current block has a strictly higher timestamp | ||
* - Current block has valid difficulty and gas limit | ||
* - In case that the header is an uncle header, it should not be too old or young in the chain. | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
* @param height - If this is an uncle header, this is the height of the block that is including it | ||
*/ | ||
validate(blockchain?: Blockchain, height?: BN): Promise<void>; | ||
validate(blockchain: Blockchain, height?: BN): Promise<void>; | ||
/** | ||
@@ -73,0 +79,0 @@ * Returns a Buffer Array of the raw Buffers in this header, in order. |
@@ -85,2 +85,3 @@ "use strict"; | ||
if (options === void 0) { options = {}; } | ||
var _a; | ||
if (options.common) { | ||
@@ -143,7 +144,15 @@ this._common = options.common; | ||
this._checkDAOExtraData(); | ||
Object.freeze(this); | ||
// Now we have set all the values of this Header, we possibly have set a dummy | ||
// `difficulty` value (defaults to 0). If we have a `calcDifficultyFromHeader` | ||
// block option parameter, we instead set difficulty to this value. | ||
if (options.calcDifficultyFromHeader) { | ||
this.difficulty = this.canonicalDifficulty(options.calcDifficultyFromHeader); | ||
} | ||
var freeze = (_a = options === null || options === void 0 ? void 0 : options.freeze) !== null && _a !== void 0 ? _a : true; | ||
if (freeze) { | ||
Object.freeze(this); | ||
} | ||
} | ||
BlockHeader.fromHeaderData = function (headerData, opts) { | ||
if (headerData === void 0) { headerData = {}; } | ||
if (opts === void 0) { opts = {}; } | ||
var parentHash = headerData.parentHash, uncleHash = headerData.uncleHash, coinbase = headerData.coinbase, stateRoot = headerData.stateRoot, transactionsTrie = headerData.transactionsTrie, receiptTrie = headerData.receiptTrie, bloom = headerData.bloom, difficulty = headerData.difficulty, number = headerData.number, gasLimit = headerData.gasLimit, gasUsed = headerData.gasUsed, timestamp = headerData.timestamp, extraData = headerData.extraData, mixHash = headerData.mixHash, nonce = headerData.nonce; | ||
@@ -171,3 +180,2 @@ return new BlockHeader(parentHash ? ethereumjs_util_1.toBuffer(parentHash) : ethereumjs_util_1.zeros(32), uncleHash ? ethereumjs_util_1.toBuffer(uncleHash) : ethereumjs_util_1.KECCAK256_RLP_ARRAY, coinbase ? new ethereumjs_util_1.Address(ethereumjs_util_1.toBuffer(coinbase)) : ethereumjs_util_1.Address.zero(), stateRoot ? ethereumjs_util_1.toBuffer(stateRoot) : ethereumjs_util_1.zeros(32), transactionsTrie ? ethereumjs_util_1.toBuffer(transactionsTrie) : ethereumjs_util_1.KECCAK256_RLP, receiptTrie ? ethereumjs_util_1.toBuffer(receiptTrie) : ethereumjs_util_1.KECCAK256_RLP, bloom ? ethereumjs_util_1.toBuffer(bloom) : ethereumjs_util_1.zeros(256), difficulty ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(difficulty)) : new ethereumjs_util_1.BN(0), number ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(number)) : new ethereumjs_util_1.BN(0), gasLimit ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(gasLimit)) : DEFAULT_GAS_LIMIT, gasUsed ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(gasUsed)) : new ethereumjs_util_1.BN(0), timestamp ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(timestamp)) : new ethereumjs_util_1.BN(0), extraData ? ethereumjs_util_1.toBuffer(extraData) : Buffer.from([]), mixHash ? ethereumjs_util_1.toBuffer(mixHash) : ethereumjs_util_1.zeros(32), nonce ? ethereumjs_util_1.toBuffer(nonce) : ethereumjs_util_1.zeros(8), opts); | ||
if (headerData === void 0) { headerData = {}; } | ||
if (opts === void 0) { opts = {}; } | ||
opts = __assign(__assign({}, opts), { initWithGenesisHeader: true }); | ||
@@ -206,2 +214,8 @@ return BlockHeader.fromHeaderData(headerData, opts); | ||
BlockHeader.prototype.canonicalDifficulty = function (parentBlockHeader) { | ||
if (this._common.consensusType() !== 'pow') { | ||
throw new Error('difficulty calculation is only supported on PoW chains'); | ||
} | ||
if (this._common.consensusAlgorithm() !== 'ethash') { | ||
throw new Error('difficulty calculation currently only supports the ethash algorithm'); | ||
} | ||
var hardfork = this._getHardfork(); | ||
@@ -221,3 +235,3 @@ var blockTs = this.timestamp; | ||
// MAX(cutoff, a) | ||
if (cutoff.cmp(a) === 1) { | ||
if (cutoff.gt(a)) { | ||
a = cutoff; | ||
@@ -253,3 +267,3 @@ } | ||
// MAX(cutoff, a) | ||
if (cutoff.cmp(a) === 1) { | ||
if (cutoff.gt(a)) { | ||
a = cutoff; | ||
@@ -261,5 +275,3 @@ } | ||
// pre-homestead | ||
if (parentTs | ||
.addn(this._common.paramByHardfork('pow', 'durationLimit', hardfork)) | ||
.cmp(blockTs) === 1) { | ||
if (parentTs.addn(this._common.paramByHardfork('pow', 'durationLimit', hardfork)).gt(blockTs)) { | ||
dif = offset.add(parentDif); | ||
@@ -275,3 +287,3 @@ } | ||
} | ||
if (dif.cmp(minimumDifficulty) === -1) { | ||
if (dif.lt(minimumDifficulty)) { | ||
dif = minimumDifficulty; | ||
@@ -287,6 +299,10 @@ } | ||
BlockHeader.prototype.validateDifficulty = function (parentBlockHeader) { | ||
if (this._common.consensusType() !== 'pow') { | ||
throw new Error('difficulty validation is currently only supported on PoW chains'); | ||
} | ||
return this.canonicalDifficulty(parentBlockHeader).eq(this.difficulty); | ||
}; | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -307,5 +323,10 @@ * @param parentBlockHeader - the header from the parent `Block` of this header | ||
/** | ||
* Validates the block header, throwing if invalid. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Validates the block header, throwing if invalid. It is being validated against the reported `parentHash`. | ||
* It verifies the current block against the `parentHash`: | ||
* - The `parentHash` is part of the blockchain (it is a valid header) | ||
* - Current block number is parent block number + 1 | ||
* - Current block has a strictly higher timestamp | ||
* - Current block has valid difficulty and gas limit | ||
* - In case that the header is an uncle header, it should not be too old or young in the chain. | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
* @param height - If this is an uncle header, this is the height of the block that is including it | ||
@@ -326,3 +347,2 @@ */ | ||
} | ||
if (!blockchain) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this._getHeaderByHash(blockchain, this.parentHash)]; | ||
@@ -341,4 +361,6 @@ case 1: | ||
} | ||
if (!this.validateDifficulty(header)) { | ||
throw new Error('invalid difficulty'); | ||
if (this._common.consensusType() === 'pow') { | ||
if (!this.validateDifficulty(header)) { | ||
throw new Error('invalid difficulty'); | ||
} | ||
} | ||
@@ -350,8 +372,7 @@ if (!this.validateGasLimit(header)) { | ||
dif = height.sub(header.number); | ||
if (!(dif.cmpn(8) === -1 && dif.cmpn(1) === 1)) { | ||
if (!(dif.ltn(8) && dif.gtn(1))) { | ||
throw new Error('uncle block has a parent that is too old or too young'); | ||
} | ||
} | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
return [2 /*return*/]; | ||
} | ||
@@ -358,0 +379,0 @@ }); |
@@ -6,2 +6,3 @@ /// <reference types="node" /> | ||
import { Block } from './block'; | ||
import { BlockHeader } from './header'; | ||
/** | ||
@@ -39,2 +40,19 @@ * An object to set to which blockchain the blocks and their headers belong. This could be specified | ||
initWithGenesisHeader?: boolean; | ||
/** | ||
* If a preceding `BlockHeader` (usually the parent header) is given the preceding | ||
* header will be used to calculate the difficulty for this block and the calculated | ||
* difficulty takes precedence over a provided static `difficulty` value. | ||
*/ | ||
calcDifficultyFromHeader?: BlockHeader; | ||
/** | ||
* A block object by default gets frozen along initialization. This gives you | ||
* strong additional security guarantees on the consistency of the block parameters. | ||
* | ||
* If you need to deactivate the block freeze - e.g. because you want to subclass block and | ||
* add aditional properties - it is strongly encouraged that you do the freeze yourself | ||
* within your code instead. | ||
* | ||
* Default: true | ||
*/ | ||
freeze?: boolean; | ||
} | ||
@@ -41,0 +59,0 @@ /** |
@@ -51,7 +51,8 @@ /// <reference types="node" /> | ||
/** | ||
* Validates the transaction trie. | ||
* Validates the transaction trie by generating a trie | ||
* and do a check on the root hash. | ||
*/ | ||
validateTransactionsTrie(): Promise<boolean>; | ||
/** | ||
* Validates the transactions. | ||
* Validates transaction signatures and minimum gas requirements. | ||
* | ||
@@ -64,8 +65,24 @@ * @param stringError - If `true`, a string with the indices of the invalid txs is returned. | ||
/** | ||
* Validates the block, throwing if invalid. | ||
* Performs the following consistency checks on the block: | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* - Value checks on the header fields | ||
* - Signature and gasLimit validation for included txs | ||
* - Validation of the tx trie | ||
* - Consistency checks and header validation of included uncles | ||
* | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
*/ | ||
validate(blockchain?: Blockchain): Promise<void>; | ||
validate(blockchain: Blockchain): Promise<void>; | ||
/** | ||
* Validates the block data, throwing if invalid. | ||
* This can be checked on the Block itself without needing access to any parent block | ||
* It checks: | ||
* - All transactions are valid | ||
* - The transactions trie is valid | ||
* - The uncle hash is valid | ||
*/ | ||
validateData(): Promise<void>; | ||
/** | ||
* Validates the uncle's hash. | ||
@@ -75,7 +92,10 @@ */ | ||
/** | ||
* Validates the uncles that are in the block, if any. This method throws if they are invalid. | ||
* Consistency checks and header validation for uncles included | ||
* in the block, if any. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - additionally validate against an @ethereumjs/blockchain instance | ||
*/ | ||
validateUncles(blockchain?: Blockchain): Promise<void>; | ||
validateUncles(blockchain: Blockchain): Promise<void>; | ||
/** | ||
@@ -94,3 +114,4 @@ * Returns the canonical difficulty for this block. | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -97,0 +118,0 @@ * @param parentBlock - the parent of this `Block` |
@@ -18,2 +18,3 @@ "use strict"; | ||
constructor(header, transactions = [], uncleHeaders = [], opts = {}) { | ||
var _a; | ||
this.transactions = []; | ||
@@ -26,5 +27,8 @@ this.uncleHeaders = []; | ||
this._common = this.header._common; | ||
Object.freeze(this); | ||
const freeze = (_a = opts === null || opts === void 0 ? void 0 : opts.freeze) !== null && _a !== void 0 ? _a : true; | ||
if (freeze) { | ||
Object.freeze(this); | ||
} | ||
} | ||
static fromBlockData(blockData = {}, opts = {}) { | ||
static fromBlockData(blockData = {}, opts) { | ||
const { header: headerData, transactions: txsData, uncleHeaders: uhsData } = blockData; | ||
@@ -44,5 +48,5 @@ const header = header_1.BlockHeader.fromHeaderData(headerData, opts); | ||
} | ||
return new Block(header, transactions, uncleHeaders); | ||
return new Block(header, transactions, uncleHeaders, opts); | ||
} | ||
static fromRLPSerializedBlock(serialized, opts = {}) { | ||
static fromRLPSerializedBlock(serialized, opts) { | ||
const values = ethereumjs_util_1.rlp.decode(serialized); | ||
@@ -54,3 +58,3 @@ if (!Array.isArray(values)) { | ||
} | ||
static fromValuesArray(values, opts = {}) { | ||
static fromValuesArray(values, opts) { | ||
if (values.length > 3) { | ||
@@ -71,3 +75,3 @@ throw new Error('invalid block. More values than expected were received'); | ||
} | ||
return new Block(header, transactions, uncleHeaders); | ||
return new Block(header, transactions, uncleHeaders, opts); | ||
} | ||
@@ -77,3 +81,3 @@ /** | ||
*/ | ||
static genesis(blockData = {}, opts = {}) { | ||
static genesis(blockData = {}, opts) { | ||
opts = Object.assign(Object.assign({}, opts), { initWithGenesisHeader: true }); | ||
@@ -123,3 +127,4 @@ return Block.fromBlockData(blockData, opts); | ||
/** | ||
* Validates the transaction trie. | ||
* Validates the transaction trie by generating a trie | ||
* and do a check on the root hash. | ||
*/ | ||
@@ -146,8 +151,27 @@ async validateTransactionsTrie() { | ||
/** | ||
* Validates the block, throwing if invalid. | ||
* Performs the following consistency checks on the block: | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* - Value checks on the header fields | ||
* - Signature and gasLimit validation for included txs | ||
* - Validation of the tx trie | ||
* - Consistency checks and header validation of included uncles | ||
* | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
*/ | ||
async validate(blockchain) { | ||
await this.header.validate(blockchain); | ||
await this.validateUncles(blockchain); | ||
await this.validateData(); | ||
} | ||
/** | ||
* Validates the block data, throwing if invalid. | ||
* This can be checked on the Block itself without needing access to any parent block | ||
* It checks: | ||
* - All transactions are valid | ||
* - The transactions trie is valid | ||
* - The uncle hash is valid | ||
*/ | ||
async validateData() { | ||
const txErrors = this.validateTransactions(true); | ||
@@ -161,3 +185,2 @@ if (txErrors.length > 0) { | ||
} | ||
await this.validateUncles(blockchain); | ||
if (!this.validateUnclesHash()) { | ||
@@ -175,5 +198,8 @@ throw new Error('invalid uncle hash'); | ||
/** | ||
* Validates the uncles that are in the block, if any. This method throws if they are invalid. | ||
* Consistency checks and header validation for uncles included | ||
* in the block, if any. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Throws if invalid. | ||
* | ||
* @param blockchain - additionally validate against an @ethereumjs/blockchain instance | ||
*/ | ||
@@ -212,3 +238,4 @@ async validateUncles(blockchain) { | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -215,0 +242,0 @@ * @param parentBlock - the parent of this `Block` |
@@ -27,4 +27,4 @@ /// <reference types="node" /> | ||
static fromHeaderData(headerData?: HeaderData, opts?: BlockOptions): BlockHeader; | ||
static fromRLPSerializedHeader(serialized: Buffer, opts: BlockOptions): BlockHeader; | ||
static fromValuesArray(values: BlockHeaderBuffer, opts: BlockOptions): BlockHeader; | ||
static fromRLPSerializedHeader(serialized: Buffer, opts?: BlockOptions): BlockHeader; | ||
static fromValuesArray(values: BlockHeaderBuffer, opts?: BlockOptions): BlockHeader; | ||
/** | ||
@@ -58,3 +58,4 @@ * Alias for Header.fromHeaderData() with initWithGenesisHeader set to true. | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -65,8 +66,13 @@ * @param parentBlockHeader - the header from the parent `Block` of this header | ||
/** | ||
* Validates the block header, throwing if invalid. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Validates the block header, throwing if invalid. It is being validated against the reported `parentHash`. | ||
* It verifies the current block against the `parentHash`: | ||
* - The `parentHash` is part of the blockchain (it is a valid header) | ||
* - Current block number is parent block number + 1 | ||
* - Current block has a strictly higher timestamp | ||
* - Current block has valid difficulty and gas limit | ||
* - In case that the header is an uncle header, it should not be too old or young in the chain. | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
* @param height - If this is an uncle header, this is the height of the block that is including it | ||
*/ | ||
validate(blockchain?: Blockchain, height?: BN): Promise<void>; | ||
validate(blockchain: Blockchain, height?: BN): Promise<void>; | ||
/** | ||
@@ -73,0 +79,0 @@ * Returns a Buffer Array of the raw Buffers in this header, in order. |
@@ -21,2 +21,3 @@ "use strict"; | ||
constructor(parentHash, uncleHash, coinbase, stateRoot, transactionsTrie, receiptTrie, bloom, difficulty, number, gasLimit, gasUsed, timestamp, extraData, mixHash, nonce, options = {}) { | ||
var _a; | ||
if (options.common) { | ||
@@ -79,5 +80,14 @@ this._common = options.common; | ||
this._checkDAOExtraData(); | ||
Object.freeze(this); | ||
// Now we have set all the values of this Header, we possibly have set a dummy | ||
// `difficulty` value (defaults to 0). If we have a `calcDifficultyFromHeader` | ||
// block option parameter, we instead set difficulty to this value. | ||
if (options.calcDifficultyFromHeader) { | ||
this.difficulty = this.canonicalDifficulty(options.calcDifficultyFromHeader); | ||
} | ||
const freeze = (_a = options === null || options === void 0 ? void 0 : options.freeze) !== null && _a !== void 0 ? _a : true; | ||
if (freeze) { | ||
Object.freeze(this); | ||
} | ||
} | ||
static fromHeaderData(headerData = {}, opts = {}) { | ||
static fromHeaderData(headerData = {}, opts) { | ||
const { parentHash, uncleHash, coinbase, stateRoot, transactionsTrie, receiptTrie, bloom, difficulty, number, gasLimit, gasUsed, timestamp, extraData, mixHash, nonce, } = headerData; | ||
@@ -103,3 +113,3 @@ return new BlockHeader(parentHash ? ethereumjs_util_1.toBuffer(parentHash) : ethereumjs_util_1.zeros(32), uncleHash ? ethereumjs_util_1.toBuffer(uncleHash) : ethereumjs_util_1.KECCAK256_RLP_ARRAY, coinbase ? new ethereumjs_util_1.Address(ethereumjs_util_1.toBuffer(coinbase)) : ethereumjs_util_1.Address.zero(), stateRoot ? ethereumjs_util_1.toBuffer(stateRoot) : ethereumjs_util_1.zeros(32), transactionsTrie ? ethereumjs_util_1.toBuffer(transactionsTrie) : ethereumjs_util_1.KECCAK256_RLP, receiptTrie ? ethereumjs_util_1.toBuffer(receiptTrie) : ethereumjs_util_1.KECCAK256_RLP, bloom ? ethereumjs_util_1.toBuffer(bloom) : ethereumjs_util_1.zeros(256), difficulty ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(difficulty)) : new ethereumjs_util_1.BN(0), number ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(number)) : new ethereumjs_util_1.BN(0), gasLimit ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(gasLimit)) : DEFAULT_GAS_LIMIT, gasUsed ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(gasUsed)) : new ethereumjs_util_1.BN(0), timestamp ? new ethereumjs_util_1.BN(ethereumjs_util_1.toBuffer(timestamp)) : new ethereumjs_util_1.BN(0), extraData ? ethereumjs_util_1.toBuffer(extraData) : Buffer.from([]), mixHash ? ethereumjs_util_1.toBuffer(mixHash) : ethereumjs_util_1.zeros(32), nonce ? ethereumjs_util_1.toBuffer(nonce) : ethereumjs_util_1.zeros(8), opts); | ||
*/ | ||
static genesis(headerData = {}, opts = {}) { | ||
static genesis(headerData = {}, opts) { | ||
opts = Object.assign(Object.assign({}, opts), { initWithGenesisHeader: true }); | ||
@@ -138,2 +148,8 @@ return BlockHeader.fromHeaderData(headerData, opts); | ||
canonicalDifficulty(parentBlockHeader) { | ||
if (this._common.consensusType() !== 'pow') { | ||
throw new Error('difficulty calculation is only supported on PoW chains'); | ||
} | ||
if (this._common.consensusAlgorithm() !== 'ethash') { | ||
throw new Error('difficulty calculation currently only supports the ethash algorithm'); | ||
} | ||
const hardfork = this._getHardfork(); | ||
@@ -153,3 +169,3 @@ const blockTs = this.timestamp; | ||
// MAX(cutoff, a) | ||
if (cutoff.cmp(a) === 1) { | ||
if (cutoff.gt(a)) { | ||
a = cutoff; | ||
@@ -185,3 +201,3 @@ } | ||
// MAX(cutoff, a) | ||
if (cutoff.cmp(a) === 1) { | ||
if (cutoff.gt(a)) { | ||
a = cutoff; | ||
@@ -193,5 +209,3 @@ } | ||
// pre-homestead | ||
if (parentTs | ||
.addn(this._common.paramByHardfork('pow', 'durationLimit', hardfork)) | ||
.cmp(blockTs) === 1) { | ||
if (parentTs.addn(this._common.paramByHardfork('pow', 'durationLimit', hardfork)).gt(blockTs)) { | ||
dif = offset.add(parentDif); | ||
@@ -207,3 +221,3 @@ } | ||
} | ||
if (dif.cmp(minimumDifficulty) === -1) { | ||
if (dif.lt(minimumDifficulty)) { | ||
dif = minimumDifficulty; | ||
@@ -219,6 +233,10 @@ } | ||
validateDifficulty(parentBlockHeader) { | ||
if (this._common.consensusType() !== 'pow') { | ||
throw new Error('difficulty validation is currently only supported on PoW chains'); | ||
} | ||
return this.canonicalDifficulty(parentBlockHeader).eq(this.difficulty); | ||
} | ||
/** | ||
* Validates the gasLimit. | ||
* Validates if the block gasLimit remains in the | ||
* boundaries set by the protocol. | ||
* | ||
@@ -239,5 +257,10 @@ * @param parentBlockHeader - the header from the parent `Block` of this header | ||
/** | ||
* Validates the block header, throwing if invalid. | ||
* | ||
* @param blockchain - additionally validate against a @ethereumjs/blockchain | ||
* Validates the block header, throwing if invalid. It is being validated against the reported `parentHash`. | ||
* It verifies the current block against the `parentHash`: | ||
* - The `parentHash` is part of the blockchain (it is a valid header) | ||
* - Current block number is parent block number + 1 | ||
* - Current block has a strictly higher timestamp | ||
* - Current block has valid difficulty and gas limit | ||
* - In case that the header is an uncle header, it should not be too old or young in the chain. | ||
* @param blockchain - validate against a @ethereumjs/blockchain | ||
* @param height - If this is an uncle header, this is the height of the block that is including it | ||
@@ -253,26 +276,26 @@ */ | ||
} | ||
if (blockchain) { | ||
const header = await this._getHeaderByHash(blockchain, this.parentHash); | ||
if (!header) { | ||
throw new Error('could not find parent header'); | ||
} | ||
const { number } = this; | ||
if (!number.eq(header.number.addn(1))) { | ||
throw new Error('invalid number'); | ||
} | ||
if (this.timestamp.lte(header.timestamp)) { | ||
throw new Error('invalid timestamp'); | ||
} | ||
const header = await this._getHeaderByHash(blockchain, this.parentHash); | ||
if (!header) { | ||
throw new Error('could not find parent header'); | ||
} | ||
const { number } = this; | ||
if (!number.eq(header.number.addn(1))) { | ||
throw new Error('invalid number'); | ||
} | ||
if (this.timestamp.lte(header.timestamp)) { | ||
throw new Error('invalid timestamp'); | ||
} | ||
if (this._common.consensusType() === 'pow') { | ||
if (!this.validateDifficulty(header)) { | ||
throw new Error('invalid difficulty'); | ||
} | ||
if (!this.validateGasLimit(header)) { | ||
throw new Error('invalid gas limit'); | ||
} | ||
if (!this.validateGasLimit(header)) { | ||
throw new Error('invalid gas limit'); | ||
} | ||
if (height) { | ||
const dif = height.sub(header.number); | ||
if (!(dif.ltn(8) && dif.gtn(1))) { | ||
throw new Error('uncle block has a parent that is too old or too young'); | ||
} | ||
if (height) { | ||
const dif = height.sub(header.number); | ||
if (!(dif.cmpn(8) === -1 && dif.cmpn(1) === 1)) { | ||
throw new Error('uncle block has a parent that is too old or too young'); | ||
} | ||
} | ||
} | ||
@@ -279,0 +302,0 @@ } |
@@ -6,2 +6,3 @@ /// <reference types="node" /> | ||
import { Block } from './block'; | ||
import { BlockHeader } from './header'; | ||
/** | ||
@@ -39,2 +40,19 @@ * An object to set to which blockchain the blocks and their headers belong. This could be specified | ||
initWithGenesisHeader?: boolean; | ||
/** | ||
* If a preceding `BlockHeader` (usually the parent header) is given the preceding | ||
* header will be used to calculate the difficulty for this block and the calculated | ||
* difficulty takes precedence over a provided static `difficulty` value. | ||
*/ | ||
calcDifficultyFromHeader?: BlockHeader; | ||
/** | ||
* A block object by default gets frozen along initialization. This gives you | ||
* strong additional security guarantees on the consistency of the block parameters. | ||
* | ||
* If you need to deactivate the block freeze - e.g. because you want to subclass block and | ||
* add aditional properties - it is strongly encouraged that you do the freeze yourself | ||
* within your code instead. | ||
* | ||
* Default: true | ||
*/ | ||
freeze?: boolean; | ||
} | ||
@@ -41,0 +59,0 @@ /** |
{ | ||
"name": "@ethereumjs/block", | ||
"version": "3.0.0-beta.1", | ||
"version": "3.0.0-beta.2", | ||
"description": "Provides Block serialization and help functions", | ||
@@ -42,4 +42,4 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@ethereumjs/common": "2.0.0-beta.1", | ||
"@ethereumjs/tx": "3.0.0-beta.1", | ||
"@ethereumjs/common": "2.0.0-beta.2", | ||
"@ethereumjs/tx": "3.0.0-beta.2", | ||
"@types/bn.js": "^4.11.6", | ||
@@ -46,0 +46,0 @@ "ethereumjs-util": "^7.0.7", |
@@ -11,2 +11,4 @@ # ethereumjs-block | ||
Note: this `README` reflects the state of the library from `v3.0.0` onwards. See `README` from the [standalone repository](https://github.com/ethereumjs/ethereumjs-block) for an introduction on the last preceeding release. | ||
# INSTALL | ||
@@ -16,6 +18,36 @@ | ||
# BROWSER | ||
# USAGE | ||
This module works with `browserify`. | ||
There are three static factories to instantiate a `Block` or `BlockHeader`: | ||
- `Block.fromBlockData(blockData: BlockData = {}, opts?: BlockOptions)` | ||
- `Block.fromRLPSerializedBlock(serialized: Buffer, opts?: BlockOptions)` | ||
- `Block.fromValuesArray(values: BlockBuffer, opts?: BlockOptions)` | ||
Instantiation Example: | ||
```typescript | ||
const headerData = { | ||
number: 15, | ||
parentHash: '0x6bfee7294bf44572b7266358e627f3c35105e1c3851f3de09e6d646f955725a7', | ||
difficulty: 131072, | ||
gasLimit: 8000000, | ||
timestamp: 1562422144, | ||
} | ||
const header = BlockHeader.fromHeaderData(headerData) | ||
``` | ||
Properties of a `Block` or `BlockHeader` object are frozen with `Object.freeze()` which gives you enhanced security and consistency properties when working with the instantiated object. This behavior can be modified using the `freeze` option in the constructor if needed. | ||
API Usage Example: | ||
```typescript | ||
try { | ||
await block.validate(blockchain) | ||
// Block validation has passed | ||
} catch (err) { | ||
// handle errors appropriately | ||
} | ||
``` | ||
# API | ||
@@ -22,0 +54,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
198757
2562
81
+ Added@ethereumjs/common@2.0.0-beta.2(transitive)
+ Added@ethereumjs/tx@3.0.0-beta.2(transitive)
- Removed@ethereumjs/common@2.0.0-beta.1(transitive)
- Removed@ethereumjs/tx@3.0.0-beta.1(transitive)
Updated@ethereumjs/tx@3.0.0-beta.2