Skip to content

Commit

Permalink
Merge pull request #930 from ethereumjs/blockchain-concurrency-and-sa…
Browse files Browse the repository at this point in the history
…fety-improvements

Blockchain concurrency and safety improvements
  • Loading branch information
holgerd77 authored Nov 9, 2020
2 parents 7371fdf + 00ef9cf commit 84aaf81
Show file tree
Hide file tree
Showing 14 changed files with 923 additions and 570 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
2 changes: 1 addition & 1 deletion packages/blockchain/src/db/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BN = require('bn.js')
import { BN } from 'ethereumjs-util'

// Geth compatible DB keys

Expand Down
78 changes: 78 additions & 0 deletions packages/blockchain/src/db/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { DBOp, DBTarget } from './operation'
import { BN, rlp } from 'ethereumjs-util'
import { Block, BlockHeader } from '@ethereumjs/block'
import { bufBE8 } from './constants'

/*
* 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), {
blockNumber,
blockHash,
})
}

/*
* 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 = []

const blockNumber = header.number
const blockHash = header.hash()

const headerValue = header.serialize()
dbOps.push(
DBOp.set(DBTarget.Header, headerValue, {
blockNumber,
blockHash,
})
)

const isGenesis = header.number.eqn(0)

if (
isGenesis ||
(blockBody instanceof Block && (blockBody.transactions.length || blockBody.uncleHeaders.length))
) {
const bodyValue = rlp.encode(blockBody.raw().slice(1))
dbOps.push(
DBOp.set(DBTarget.Body, bodyValue, {
blockNumber,
blockHash,
})
)
}

return dbOps
}

function DBSetHashToNumber(blockHash: Buffer, blockNumber: BN): DBOp {
const blockNumber8Byte = bufBE8(blockNumber)
return DBOp.set(DBTarget.HashToNumber, blockNumber8Byte, {
blockHash,
})
}

function DBSaveLookups(blockHash: Buffer, blockNumber: BN): DBOp[] {
const ops = []
ops.push(DBOp.set(DBTarget.NumberToHash, blockHash, { blockNumber }))

const blockNumber8Bytes = bufBE8(blockNumber)
ops.push(
DBOp.set(DBTarget.HashToNumber, blockNumber8Bytes, {
blockHash,
})
)
return ops
}

export { DBOp, DBSetTD, DBSetBlockOrHeader, DBSetHashToNumber, DBSaveLookups }
6 changes: 3 additions & 3 deletions packages/blockchain/src/db/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export type CacheMap = { [key: string]: Cache<Buffer> }
* @hidden
*/
export class DBManager {
_cache: CacheMap
_common: Common
_db: LevelUp
private _cache: CacheMap
private _common: Common
private _db: LevelUp

constructor(db: LevelUp, common: Common) {
this._db = db
Expand Down
Loading

0 comments on commit 84aaf81

Please sign in to comment.