Skip to content

Commit

Permalink
blockchain: added v5.0.0-beta.2 CHANGELOG, some comment streamlining,…
Browse files Browse the repository at this point in the history
… inlined _getCanonicalGenesisBlock() function
  • Loading branch information
holgerd77 committed Nov 9, 2020
1 parent 0339b06 commit 00ef9cf
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 53 deletions.
35 changes: 35 additions & 0 deletions packages/blockchain/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,41 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
(modification: no type change headlines) and this project adheres to
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 5.0.0-beta.2 - UNRELEASED

This is the second beta release towards a final `v5.0.0` `Blockchain` library release, see [v5.0.0-beta.1 release notes](https://github.com/ethereumjs/ethereumjs-vm/releases/tag/%40ethereumjs%2Fblockchain%405.0.0-beta.1) for an overview on the full changes since the last publicly released version.

This release introduces **new breaking changes**, so please carefully read the additional release note sections!

**Safe Static Constructor**

The library now has an additional safe static constructor `Blockchain.create()` which awaits the init method and throws if the init method throws:

```typescript
const common = new Common({ chain: 'ropsten' })
const blockchain = await Blockchain.create({ common })
```

This is the new recommended way to instantiate a `Blockchain` object, see PR [#930](https://github.com/ethereumjs/ethereumjs-vm/pull/930).

**Refactored Genesis Block Handling Mechanism**

Genesis handling has been reworked to now be safer and reduce the risk of wiping a blockchain by setting a new genesis, see PR [#930](https://github.com/ethereumjs/ethereumjs-vm/pull/930).

**Breaking**: The dedicated `setGenesisBlock()` methods and the optional `isGenesis` option on `Blockchain.putBlock()` have been removed. Instead the genesis block is created on initialization either from the `Common` library instance passed or a custom genesis block passed along with the `genesisBlock` option. If a custom genesis block is used, this custom block now always has to be passed along on `Blockchain` initialization, also when operating on an already existing DB.

**Changes and Refactoring**

- Refactored `DBManager` with the introduction of an abstract DB operation handling mechanism, if you have modified `DBManager` in your code this will be a **potentially breaking** change for you, PR [#927](https://github.com/ethereumjs/ethereumjs-vm/pull/927)
- Renaming of internal variables like `Blockchain._headBlock`, if you are using these variables in your code this will be a **potentially breaking** change for you, PR [#930](https://github.com/ethereumjs/ethereumjs-vm/pull/930)
- Made internal `_` methods like `_saveHeads()` private, if you are using these functions in your code this will be a **potentially breaking** change for you, PR [#930](https://github.com/ethereumjs/ethereumjs-vm/pull/930)
- Improved code documentation, PR [#930](https://github.com/ethereumjs/ethereumjs-vm/pull/930)
- Fixed potential blockchain DB concurrency issues along PR [#930](https://github.com/ethereumjs/ethereumjs-vm/pull/930)

**Testing and CI**

- Dedicated `blockchain` reorg test setup and executable test, PR [#926](https://github.com/ethereumjs/ethereumjs-vm/pull/926)

## 5.0.0-beta.1 - 2020-10-22

### New Package Name
Expand Down
17 changes: 9 additions & 8 deletions packages/blockchain/src/db/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { Block, BlockHeader } from '@ethereumjs/block'
import { bufBE8 } from './constants'

/*
This extra helper file is an interface between blockchain / operation.ts
It also handles the right encoding of the keys, so this does not have to happen in index.ts anymore.
*/
* This extra helper file serves as an interface between the blockchain API functionality
* and the DB operations from `db/operation.ts` and also handles the right encoding of the keys
*/

function DBSetTD(TD: BN, blockNumber: BN, blockHash: Buffer): DBOp {
return DBOp.set(DBTarget.TotalDifficulty, rlp.encode(TD), {
Expand All @@ -16,11 +16,12 @@ function DBSetTD(TD: BN, blockNumber: BN, blockHash: Buffer): DBOp {
}

/*
This method accepts either a BlockHeader or a Block and returns a list of DatabaseOperation
This always consists of a Set Header operation
It could also consist of a set body operation: this only happens if the body is not empty (it has transactions/uncles), or it is the genesis block
If the block is empty, we do not have to save it; the DB will assume that if the Header exists, but no block body, then the block was empty.
*/
* This method accepts either a BlockHeader or a Block and returns a list of DatabaseOperation instances
*
* - A "Set Header Operation" is always added
* - A "Set Body Operation" is only added if the body is not empty (it has transactions/uncles) or if the block is the genesis block
* (if there is a header but no block saved the DB will implicitly assume the block to be empty)
*/
function DBSetBlockOrHeader(blockBody: Block | BlockHeader): DBOp[] {
const header: BlockHeader = blockBody instanceof Block ? blockBody.header : blockBody
const dbOps = []
Expand Down
85 changes: 40 additions & 45 deletions packages/blockchain/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,15 @@ export default class Blockchain implements BlockchainInterface {

private _genesis?: Buffer // the genesis hash of this blockchain

// The following three head hashes (or maps) never point to a stale hash and
// always point to a hash in the canonical chain However, these might point to
// a different hash than the hash with the highest Total Difficulty, with the
// exception of the _headHeaderHash The _headHeaderHash always points to the
// head with the highest total difficulty.
// The following two heads and the heads stored within the `_heads` always point
// to a hash in the canonical chain and never to a stale hash.
// With the exception of `_headHeaderHash` this does not necessarily need to be
// the hash with the highest total difficulty.
private _headBlockHash?: Buffer // the hash of the current head block
private _headHeaderHash?: Buffer // the hash of the current head header
// a Map which stores the head of each key (for instance the "vm" key) this is
// updated if you run the iterator method and can be used to (re)run
// non-verified blocks, for instance, in the VM.
// A Map which stores the head of each key (for instance the "vm" key) which is
// updated along an `iterator()` method run and can be used to (re)run
// non-verified blocks (for instance in the VM).
private _heads: { [key: string]: Buffer }

public initPromise: Promise<void>
Expand Down Expand Up @@ -189,7 +188,7 @@ export default class Blockchain implements BlockchainInterface {
}

/**
* This method is called in the constructor and either setups the DB or reads
* This method is called in the constructor and either sets up the DB or reads
* values from the DB and makes these available to the consumers of
* Blockchain.
*
Expand All @@ -207,11 +206,15 @@ export default class Blockchain implements BlockchainInterface {
}

if (!genesisBlock) {
genesisBlock = this._getCanonicalGenesisBlock()
const common = new Common({
chain: this._common.chainId(),
hardfork: 'chainstart',
})
genesisBlock = Block.genesis({}, { common })
}

// if the DB has a genesis block, then verify that the genesis block in the
// DB is indeed the Genesis block we either generated, or got assigned.
// If the DB has a genesis block, then verify that the genesis block in the
// DB is indeed the Genesis block generated or assigned.
if (DBGenesisBlock && !genesisBlock.hash().equals(DBGenesisBlock.hash())) {
throw new Error(
'The genesis block in the DB has a different hash than the provided genesis block.'
Expand All @@ -221,16 +224,16 @@ export default class Blockchain implements BlockchainInterface {
const genesisHash = genesisBlock.hash()

if (!DBGenesisBlock) {
// there is no genesis block. we thus have to put the genesis block in the
// DB we have to save the TD, the BlockOrHeader, and the Lookups
// If there is no genesis block put the genesis block in the DB.
// For that TD, the BlockOrHeader, and the Lookups have to be saved.
const dbOps: DBOp[] = []
dbOps.push(DBSetTD(genesisBlock.header.difficulty.clone(), new BN(0), genesisHash))
DBSetBlockOrHeader(genesisBlock).map((op) => dbOps.push(op))
DBSaveLookups(genesisHash, new BN(0)).map((op) => dbOps.push(op))
await this.dbManager.batch(dbOps)
}

// at this point, we can safely set genesisHash as the _genesis hash in this
// At this point, we can safely set genesisHash as the _genesis hash in this
// object: it is either the one we put in the DB, or it is equal to the one
// which we read from the DB.
this._genesis = genesisHash
Expand Down Expand Up @@ -298,20 +301,6 @@ export default class Blockchain implements BlockchainInterface {
}
}

/**
* Sets the default genesis block
*
* @hidden
*/
private _getCanonicalGenesisBlock(): Block {
const common = new Common({
chain: this._common.chainId(),
hardfork: 'chainstart',
})
const genesis = Block.genesis({}, { common })
return genesis
}

/**
* Returns the specified iterator head.
*
Expand Down Expand Up @@ -359,10 +348,11 @@ export default class Blockchain implements BlockchainInterface {
}

/**
* Adds many blocks to the blockchain. If any of the blocks is invalid, this
* function will throw; the blocks before this block will be put in the DB,
* but the blocks after will not be put in If any of these blocks has a higher
* total difficulty than the current max total difficulty, then the canonical
* Adds blocks to the blockchain.
*
* If an invalid block is met the function will throw, blocks before will
* nevertheless remain in the DB. If any of the saved blocks has a higher
* total difficulty than the current max total difficulty the canonical
* chain is rebuilt and any stale heads/hashes are overwritten.
* @param blocks - The blocks to be added to the blockchain
*/
Expand All @@ -374,9 +364,11 @@ export default class Blockchain implements BlockchainInterface {
}

/**
* Adds a block to the blockchain. If this block is valid, and it has a higher
* total difficulty than the current max total difficulty, the canonical chain
* is rebuilt and any stale heads/hashes are overwritten.
* Adds a block to the blockchain.
*
* If the block is valid and has a higher total difficulty than the current
* max total difficulty, the canonical chain is rebuilt and any stale
* heads/hashes are overwritten.
* @param block - The block to be added to the blockchain
*/
async putBlock(block: Block) {
Expand All @@ -385,11 +377,12 @@ export default class Blockchain implements BlockchainInterface {
}

/**
* Adds many headers to the blockchain. If any of the headers is invalid, this
* function will throw; The headers before this header will be put in the DB,
* but the headers after will not be put in If any of these headers has a
* higher total difficulty than the current max total difficulty, then the
* canonical chain is rebuilt and any stale heads/hashes are overwritten.
* Adds many headers to the blockchain.
*
* If an invalid header is met the function will throw, headers before will
* nevertheless remain in the DB. If any of the saved headers has a higher
* total difficulty than the current max total difficulty the canonical
* chain is rebuilt and any stale heads/hashes are overwritten.
* @param headers - The headers to be added to the blockchain
*/
async putHeaders(headers: Array<any>) {
Expand All @@ -400,9 +393,11 @@ export default class Blockchain implements BlockchainInterface {
}

/**
* Adds a header to the blockchain. If this header is valid, and it has a
* higher total difficulty than the current max total difficulty, the
* canonical chain is rebuilt and any stale heads/hashes are overwritten.
* Adds a header to the blockchain.
*
* If this header is valid and it has a higher total difficulty than the current
* max total difficulty, the canonical chain is rebuilt and any stale
* heads/hashes are overwritten.
* @param header - The header to be added to the blockchain
*/
async putHeader(header: BlockHeader) {
Expand All @@ -411,7 +406,7 @@ export default class Blockchain implements BlockchainInterface {
}

/**
* Entry point for putting any block or block header. Verifies this block,
* Entrypoint for putting any block or block header. Verifies this block,
* checks the total TD: if this TD is higher than the current highest TD, we
* have thus found a new canonical block and have to rewrite the canonical
* chain. This also updates the head block hashes. If any of the older known
Expand Down

0 comments on commit 00ef9cf

Please sign in to comment.