@rei-network/blockchain
Advanced tools
Comparing version 2.0.0 to 2.0.1
@@ -0,3 +1,3 @@ | ||
/// <reference types="bn.js" /> | ||
/// <reference types="node" /> | ||
/// <reference types="bn.js" /> | ||
import { Address, BN } from 'ethereumjs-util'; | ||
@@ -12,2 +12,5 @@ import { Block, BlockData, BlockHeader, Receipt } from '@rei-network/structure'; | ||
} | ||
export interface ForcePutBlockOptions extends PutBlockOptions { | ||
td: BN; | ||
} | ||
export interface BlockchainInterface { | ||
@@ -338,2 +341,6 @@ /** | ||
/** | ||
* Force update current header | ||
*/ | ||
forcePutBlock(item: Block | BlockHeader, options: ForcePutBlockOptions): Promise<boolean>; | ||
/** | ||
* Gets a block by its hash. | ||
@@ -340,0 +347,0 @@ * |
{ | ||
"name": "@rei-network/blockchain", | ||
"version": "2.0.0", | ||
"version": "2.0.1", | ||
"main": "dist/index.js", | ||
@@ -9,3 +9,3 @@ "types": "dist/index.d.ts", | ||
"build": "tsc --build tsconfig.json", | ||
"test": "echo @rei-network/blockchain has no test cases" | ||
"test": "mocha -r ts-node/register 'test/**/*.test.ts' --exit" | ||
}, | ||
@@ -18,4 +18,4 @@ "devDependencies": { | ||
"dependencies": { | ||
"@rei-network/common": "^2.0.0", | ||
"@rei-network/database": "^2.0.0", | ||
"@rei-network/common": "^2.0.1", | ||
"@rei-network/database": "^2.0.1", | ||
"@rei-network/structure": "^1.0.0", | ||
@@ -22,0 +22,0 @@ "debug": "^4.3.3", |
136
src/index.ts
@@ -20,2 +20,7 @@ import { debug as createDebugLogger } from 'debug'; | ||
export interface ForcePutBlockOptions extends PutBlockOptions { | ||
// Total difficulty | ||
td: BN; | ||
} | ||
export interface BlockchainInterface { | ||
@@ -956,2 +961,133 @@ /** | ||
/** | ||
* Force update current header | ||
*/ | ||
async forcePutBlock(item: Block | BlockHeader, options: ForcePutBlockOptions) { | ||
return await this.runWithLock<boolean>(async () => { | ||
const block = | ||
item instanceof BlockHeader | ||
? new Block(item, undefined, undefined, { | ||
common: this._common, | ||
hardforkByBlockNumber: true | ||
}) | ||
: item; | ||
const isGenesis = block.isGenesis(); | ||
const isHeader = item instanceof BlockHeader; | ||
// we cannot overwrite the Genesis block after initializing the Blockchain | ||
if (isGenesis) { | ||
throw new Error('Cannot put a genesis block: create a new Blockchain'); | ||
} | ||
const { header } = block; | ||
const blockHash = header.hash(); | ||
const blockNumber = header.number; | ||
let dbOps: DBOp[] = []; | ||
if (!block._common.chainIdBN().eq(this._common.chainIdBN())) { | ||
throw new Error('Chain mismatch while trying to put block or header'); | ||
} | ||
if (this._validateBlocks && !isGenesis) { | ||
// this calls into `getBlock`, which is why we cannot lock yet | ||
await block.validate(this, isHeader); | ||
} | ||
if (this._validateConsensus) { | ||
if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Ethash) { | ||
// do nothing | ||
} | ||
if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Clique) { | ||
const valid = header.cliqueVerifySignature(this.cliqueActiveSigners()); | ||
if (!valid) { | ||
throw new Error('invalid PoA block signature (clique)'); | ||
} | ||
if (this.cliqueCheckRecentlySigned(header)) { | ||
throw new Error('recently signed'); | ||
} | ||
// validate checkpoint signers towards active signers on epoch transition blocks | ||
if (header.cliqueIsEpochTransition()) { | ||
// note: keep votes on epoch transition blocks in case of reorgs. | ||
// only active (non-stale) votes will counted (if vote.blockNumber >= lastEpochBlockNumber) | ||
const checkpointSigners = header.cliqueEpochTransitionSigners(); | ||
const activeSigners = this.cliqueActiveSigners(); | ||
for (const [i, cSigner] of checkpointSigners.entries()) { | ||
if (!activeSigners[i] || !activeSigners[i].equals(cSigner)) { | ||
throw new Error(`checkpoint signer not found in active signers list at index ${i}: ${cSigner.toString()}`); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
if (block._common.consensusType() !== ConsensusType.ProofOfStake) { | ||
// load total difficulty from input options | ||
const td = options.td; | ||
// save total difficulty to the database | ||
dbOps = dbOps.concat(DBSetTD(td, blockNumber, blockHash)); | ||
} | ||
// save header/block to the database | ||
dbOps = dbOps.concat(DBSetBlockOrHeader(block)); | ||
// save receipts to the database | ||
options?.receipts && (dbOps = dbOps.concat(DBSaveReceipts(options.receipts, blockHash, blockNumber))); | ||
// save tx lookup to the database | ||
options?.saveTxLookup && (dbOps = dbOps.concat(DBSaveTxLookup(block))); | ||
let ancientHeaderNumber: undefined | BN; | ||
// force reorg | ||
const reorg = true; | ||
// if total difficulty is higher than current, add it to canonical chain | ||
if (reorg) { | ||
if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Clique) { | ||
ancientHeaderNumber = (await this._findAncient(header)).number; | ||
} | ||
this._headHeaderHash = blockHash; | ||
if (item instanceof Block) { | ||
this._headBlockHash = blockHash; | ||
} | ||
if (this._hardforkByHeadBlockNumber) { | ||
this._common.setHardforkByBlockNumber(blockNumber); | ||
} | ||
// TODO SET THIS IN CONSTRUCTOR | ||
if (block.isGenesis()) { | ||
this._genesis = blockHash; | ||
} | ||
// delete higher number assignments and overwrite stale canonical chain | ||
await this._deleteCanonicalChainReferences(blockNumber.addn(1), blockHash, dbOps); | ||
// from the current header block, check the blockchain in reverse (i.e. | ||
// traverse `parentHash`) until `numberToHash` matches the current | ||
// number/hash in the canonical chain also: overwrite any heads if these | ||
// heads are stale in `_heads` and `_headBlockHash` | ||
await this._rebuildCanonical(header, dbOps); | ||
} | ||
const ops = dbOps.concat(this._saveHeadOps()); | ||
await this.database.batch(ops); | ||
// Clique: update signer votes and state | ||
if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Clique && ancientHeaderNumber) { | ||
await this._cliqueDeleteSnapshots(ancientHeaderNumber.addn(1)); | ||
for (const number = ancientHeaderNumber.addn(1); number.lte(header.number); number.iaddn(1)) { | ||
const canonicalHeader = await this._getCanonicalHeader(number); | ||
await this._cliqueBuildSnapshots(canonicalHeader); | ||
} | ||
} | ||
if (reorg) { | ||
await this.updateLatest(); | ||
} | ||
return reorg; | ||
}); | ||
} | ||
/** | ||
* Gets a block by its hash. | ||
@@ -958,0 +1094,0 @@ * |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
192133
12
3588
1
1
Updated@rei-network/common@^2.0.1
Updated@rei-network/database@^2.0.1