implement forkid calculation and tests for each supported network
This commit is contained in:
parent
069e125f98
commit
e37cacd8f1
|
@ -1,17 +1,100 @@
|
||||||
import ../db/db_chain, eth/common, chronicles, ../vm_state, ../vm_types,
|
import ../db/db_chain, eth/common, chronicles, ../vm_state, ../vm_types,
|
||||||
../vm/[computation, message], stint, nimcrypto,
|
../vm/[computation, message], ../vm/interpreter/vm_forks, stint, nimcrypto,
|
||||||
../utils, eth/trie/db, ../tracer, ./executor
|
../utils, eth/trie/db, ../tracer, ./executor, ../config, ../genesis, ../utils,
|
||||||
|
stew/endians2
|
||||||
|
|
||||||
type
|
type
|
||||||
|
# Chain's forks not always equals to EVM's forks
|
||||||
|
ChainFork = enum
|
||||||
|
Frontier,
|
||||||
|
Homestead,
|
||||||
|
DAOFork,
|
||||||
|
Tangerine,
|
||||||
|
Spurious,
|
||||||
|
Byzantium,
|
||||||
|
Constantinople,
|
||||||
|
Petersburg,
|
||||||
|
Istanbul,
|
||||||
|
MuirGlacier
|
||||||
|
|
||||||
Chain* = ref object of AbstractChainDB
|
Chain* = ref object of AbstractChainDB
|
||||||
db: BaseChainDB
|
db: BaseChainDB
|
||||||
|
forkIds: array[ChainFork, ForkID]
|
||||||
|
blockZeroHash: KeccakHash
|
||||||
|
|
||||||
|
func toChainFork(c: ChainConfig, number: BlockNumber): ChainFork =
|
||||||
|
if number >= c.muirGlacierBlock: MuirGlacier
|
||||||
|
elif number >= c.istanbulBlock: Istanbul
|
||||||
|
elif number >= c.petersburgBlock: Petersburg
|
||||||
|
elif number >= c.constantinopleBlock: Constantinople
|
||||||
|
elif number >= c.byzantiumBlock: Byzantium
|
||||||
|
elif number >= c.eip158Block: Spurious
|
||||||
|
elif number >= c.eip150Block: Tangerine
|
||||||
|
elif number >= c.daoForkBlock: DAOFork
|
||||||
|
elif number >= c.homesteadBlock: Homestead
|
||||||
|
else: Frontier
|
||||||
|
|
||||||
|
func toNextFork(n: BlockNumber): uint64 =
|
||||||
|
if n == high(BlockNumber):
|
||||||
|
result = 0'u64
|
||||||
|
else:
|
||||||
|
result = n.truncate(uint64)
|
||||||
|
|
||||||
|
func getNextFork(c: ChainConfig, fork: ChainFork): uint64 =
|
||||||
|
let next: array[ChainFork, uint64] = [
|
||||||
|
0'u64,
|
||||||
|
toNextFork(c.homesteadBlock),
|
||||||
|
toNextFork(c.daoForkBlock),
|
||||||
|
toNextFork(c.eip150Block),
|
||||||
|
toNextFork(c.eip158Block),
|
||||||
|
toNextFork(c.byzantiumBlock),
|
||||||
|
toNextFork(c.constantinopleBlock),
|
||||||
|
toNextFork(c.petersburgBlock),
|
||||||
|
toNextFork(c.istanbulBlock),
|
||||||
|
toNextFork(c.muirGlacierBlock),
|
||||||
|
]
|
||||||
|
|
||||||
|
if fork == high(ChainFork):
|
||||||
|
result = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
result = next[fork]
|
||||||
|
for x in fork..high(ChainFork):
|
||||||
|
if result != next[x]:
|
||||||
|
result = next[x]
|
||||||
|
break
|
||||||
|
|
||||||
|
func calculateForkId(c: ChainConfig, fork: ChainFork, prevCRC: uint32, prevFork: uint64): ForkID =
|
||||||
|
result.nextFork = c.getNextFork(fork)
|
||||||
|
|
||||||
|
if result.nextFork != prevFork:
|
||||||
|
result.crc = crc32(prevCRC, toBytesBE(prevFork))
|
||||||
|
else:
|
||||||
|
result.crc = prevCRC
|
||||||
|
|
||||||
|
func calculateForkIds(c: ChainConfig, genesisCRC: uint32): array[ChainFork, ForkID] =
|
||||||
|
var prevCRC = genesisCRC
|
||||||
|
var prevFork = c.getNextFork(Frontier)
|
||||||
|
|
||||||
|
for fork in ChainFork:
|
||||||
|
result[fork] = calculateForkId(c, fork, prevCRC, prevFork)
|
||||||
|
prevFork = result[fork].nextFork
|
||||||
|
prevCRC = result[fork].crc
|
||||||
|
|
||||||
proc newChain*(db: BaseChainDB): Chain =
|
proc newChain*(db: BaseChainDB): Chain =
|
||||||
result.new
|
result.new
|
||||||
result.db = db
|
result.db = db
|
||||||
|
|
||||||
|
if not db.config.daoForkSupport:
|
||||||
|
db.config.daoForkBlock = db.config.homesteadBlock
|
||||||
|
let chainId = PublicNetwork(db.config.chainId)
|
||||||
|
let g = defaultGenesisBlockForNetwork(chainId)
|
||||||
|
result.blockZeroHash = g.toBlock.blockHash
|
||||||
|
let genesisCRC = crc32(0, result.blockZeroHash.data)
|
||||||
|
result.forkIds = calculateForkIds(db.config, genesisCRC)
|
||||||
|
|
||||||
method genesisHash*(c: Chain): KeccakHash {.gcsafe.} =
|
method genesisHash*(c: Chain): KeccakHash {.gcsafe.} =
|
||||||
c.db.getBlockHash(0.toBlockNumber)
|
c.blockZeroHash
|
||||||
|
|
||||||
method getBlockHeader*(c: Chain, b: HashOrNum, output: var BlockHeader): bool {.gcsafe.} =
|
method getBlockHeader*(c: Chain, b: HashOrNum, output: var BlockHeader): bool {.gcsafe.} =
|
||||||
case b.isHash
|
case b.isHash
|
||||||
|
@ -73,3 +156,7 @@ method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarr
|
||||||
method getTrieDB*(c: Chain): TrieDatabaseRef {.gcsafe.} =
|
method getTrieDB*(c: Chain): TrieDatabaseRef {.gcsafe.} =
|
||||||
c.db.db
|
c.db.db
|
||||||
|
|
||||||
|
method getForkId*(c: Chain, n: BlockNumber): ForkID {.gcsafe.} =
|
||||||
|
# EIP 2364/2124
|
||||||
|
let fork = c.db.config.toChainFork(n)
|
||||||
|
c.forkIds[fork]
|
||||||
|
|
|
@ -38,3 +38,15 @@ func generateSafeAddress*(address: EthAddress, salt: Uint256, data: openArray[by
|
||||||
|
|
||||||
func hash*(b: BlockHeader): Hash256 {.inline.} =
|
func hash*(b: BlockHeader): Hash256 {.inline.} =
|
||||||
rlpHash(b)
|
rlpHash(b)
|
||||||
|
|
||||||
|
proc crc32*(crc: uint32, buf: openArray[byte]): uint32 =
|
||||||
|
const kcrc32 = [ 0'u32, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,
|
||||||
|
0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320'u32, 0xf00f9344'u32, 0xd6d6a3e8'u32,
|
||||||
|
0xcb61b38c'u32, 0x9b64c2b0'u32, 0x86d3d2d4'u32, 0xa00ae278'u32, 0xbdbdf21c'u32]
|
||||||
|
|
||||||
|
var crcu32 = not crc
|
||||||
|
for b in buf:
|
||||||
|
crcu32 = (crcu32 shr 4) xor kcrc32[int((crcu32 and 0xF) xor (uint32(b) and 0xF'u32))]
|
||||||
|
crcu32 = (crcu32 shr 4) xor kcrc32[int((crcu32 and 0xF) xor (uint32(b) shr 4'u32))]
|
||||||
|
|
||||||
|
result = not crcu32
|
||||||
|
|
|
@ -108,6 +108,7 @@ cliBuilder:
|
||||||
./test_difficulty,
|
./test_difficulty,
|
||||||
./test_transaction_json,
|
./test_transaction_json,
|
||||||
./test_blockchain_json,
|
./test_blockchain_json,
|
||||||
|
./test_forkid,
|
||||||
../stateless/test_witness_keys,
|
../stateless/test_witness_keys,
|
||||||
../stateless/test_block_witness,
|
../stateless/test_block_witness,
|
||||||
../stateless/test_witness_json
|
../stateless/test_witness_json
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import
|
||||||
|
unittest2, eth/common, eth/trie/db,
|
||||||
|
../nimbus/db/db_chain, ../nimbus/p2p/chain,
|
||||||
|
../nimbus/config
|
||||||
|
|
||||||
|
const
|
||||||
|
MainNetIDs = [
|
||||||
|
(blockNumber: 0'u64, id: (crc: 0xfc64ec04'u32, nextFork: 1150000'u64)), # Unsynced
|
||||||
|
(blockNumber: 1149999'u64, id: (crc: 0xfc64ec04'u32, nextFork: 1150000'u64)), # Last Frontier block
|
||||||
|
(blockNumber: 1150000'u64, id: (crc: 0x97c2c34c'u32, nextFork: 1920000'u64)), # First Homestead block
|
||||||
|
(blockNumber: 1919999'u64, id: (crc: 0x97c2c34c'u32, nextFork: 1920000'u64)), # Last Homestead block
|
||||||
|
(blockNumber: 1920000'u64, id: (crc: 0x91d1f948'u32, nextFork: 2463000'u64)), # First DAO block
|
||||||
|
(blockNumber: 2462999'u64, id: (crc: 0x91d1f948'u32, nextFork: 2463000'u64)), # Last DAO block
|
||||||
|
(blockNumber: 2463000'u64, id: (crc: 0x7a64da13'u32, nextFork: 2675000'u64)), # First Tangerine block
|
||||||
|
(blockNumber: 2674999'u64, id: (crc: 0x7a64da13'u32, nextFork: 2675000'u64)), # Last Tangerine block
|
||||||
|
(blockNumber: 2675000'u64, id: (crc: 0x3edd5b10'u32, nextFork: 4370000'u64)), # First Spurious block
|
||||||
|
(blockNumber: 4369999'u64, id: (crc: 0x3edd5b10'u32, nextFork: 4370000'u64)), # Last Spurious block
|
||||||
|
(blockNumber: 4370000'u64, id: (crc: 0xa00bc324'u32, nextFork: 7280000'u64)), # First Byzantium block
|
||||||
|
(blockNumber: 7279999'u64, id: (crc: 0xa00bc324'u32, nextFork: 7280000'u64)), # Last Byzantium block
|
||||||
|
(blockNumber: 7280000'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # First and last Constantinople, first Petersburg block
|
||||||
|
(blockNumber: 7987396'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # Past Petersburg block
|
||||||
|
(blockNumber: 9068999'u64, id: (crc: 0x668db0af'u32, nextFork: 9069000'u64)), # Last Petersburg block
|
||||||
|
(blockNumber: 9069000'u64, id: (crc: 0x879D6E30'u32, nextFork: 9200000'u64)), # First Istanbul block
|
||||||
|
(blockNumber: 9199999'u64, id: (crc: 0x879D6E30'u32, nextFork: 9200000'u64)), # Last Istanbul block
|
||||||
|
(blockNumber: 9200000'u64, id: (crc: 0xE029E991'u32, nextFork: 0'u64)) , # First MuirGlacier block
|
||||||
|
(blockNumber: 10000000'u64, id: (crc: 0xE029E991'u32, nextFork: 0'u64)) , # Past MuirGlacier block
|
||||||
|
]
|
||||||
|
|
||||||
|
RopstenNetIDs = [
|
||||||
|
(blockNumber: 0'u64, id: (crc: 0x30c7ddbc'u32, nextFork: 10'u64)), # Unsynced, last Frontier, Homestead and first Tangerine block
|
||||||
|
(blockNumber: 9'u64, id: (crc: 0x30c7ddbc'u32, nextFork: 10'u64)), # Last Tangerine block
|
||||||
|
(blockNumber: 10'u64, id: (crc: 0x63760190'u32, nextFork: 1700000'u64)), # First Spurious block
|
||||||
|
(blockNumber: 1699999'u64, id: (crc: 0x63760190'u32, nextFork: 1700000'u64)), # Last Spurious block
|
||||||
|
(blockNumber: 1700000'u64, id: (crc: 0x3ea159c7'u32, nextFork: 4230000'u64)), # First Byzantium block
|
||||||
|
(blockNumber: 4229999'u64, id: (crc: 0x3ea159c7'u32, nextFork: 4230000'u64)), # Last Byzantium block
|
||||||
|
(blockNumber: 4230000'u64, id: (crc: 0x97b544f3'u32, nextFork: 4939394'u64)), # First Constantinople block
|
||||||
|
(blockNumber: 4939393'u64, id: (crc: 0x97b544f3'u32, nextFork: 4939394'u64)), # Last Constantinople block
|
||||||
|
(blockNumber: 4939394'u64, id: (crc: 0xd6e2149b'u32, nextFork: 6485846'u64)), # First Petersburg block
|
||||||
|
(blockNumber: 6485845'u64, id: (crc: 0xd6e2149b'u32, nextFork: 6485846'u64)), # Last Petersburg block
|
||||||
|
(blockNumber: 6485846'u64, id: (crc: 0x4bc66396'u32, nextFork: 7117117'u64)), # First Istanbul block
|
||||||
|
(blockNumber: 7117116'u64, id: (crc: 0x4bc66396'u32, nextFork: 7117117'u64)), # Last Istanbul block
|
||||||
|
(blockNumber: 7117117'u64, id: (crc: 0x6727EF90'u32, nextFork: 0'u64)), # First MuirGlacier block
|
||||||
|
(blockNumber: 7500000'u64, id: (crc: 0x6727EF90'u32, nextFork: 0'u64)), # Future MuirGlacier block
|
||||||
|
]
|
||||||
|
|
||||||
|
RinkebyNetIDs = [
|
||||||
|
(blockNumber: 0'u64, id: (crc: 0x3b8e0691'u32, nextFork: 1'u64)), # Unsynced, last Frontier block
|
||||||
|
(blockNumber: 1'u64, id: (crc: 0x60949295'u32, nextFork: 2'u64)), # First and last Homestead block
|
||||||
|
(blockNumber: 2'u64, id: (crc: 0x8bde40dd'u32, nextFork: 3'u64)), # First and last Tangerine block
|
||||||
|
(blockNumber: 3'u64, id: (crc: 0xcb3a64bb'u32, nextFork: 1035301'u64)), # First Spurious block
|
||||||
|
(blockNumber: 1035300'u64, id: (crc: 0xcb3a64bb'u32, nextFork: 1035301'u64)), # Last Spurious block
|
||||||
|
(blockNumber: 1035301'u64, id: (crc: 0x8d748b57'u32, nextFork: 3660663'u64)), # First Byzantium block
|
||||||
|
(blockNumber: 3660662'u64, id: (crc: 0x8d748b57'u32, nextFork: 3660663'u64)), # Last Byzantium block
|
||||||
|
(blockNumber: 3660663'u64, id: (crc: 0xe49cab14'u32, nextFork: 4321234'u64)), # First Constantinople block
|
||||||
|
(blockNumber: 4321233'u64, id: (crc: 0xe49cab14'u32, nextFork: 4321234'u64)), # Last Constantinople block
|
||||||
|
(blockNumber: 4321234'u64, id: (crc: 0xafec6b27'u32, nextFork: 5435345'u64)), # First Petersburg block
|
||||||
|
(blockNumber: 5435344'u64, id: (crc: 0xafec6b27'u32, nextFork: 5435345'u64)), # Last Petersburg block
|
||||||
|
(blockNumber: 5435345'u64, id: (crc: 0xcbdb8838'u32, nextFork: 0'u64)), # First Istanbul block
|
||||||
|
(blockNumber: 6000000'u64, id: (crc: 0xcbdb8838'u32, nextFork: 0'u64)), # Future Istanbul block
|
||||||
|
]
|
||||||
|
|
||||||
|
GoerliNetIDs = [
|
||||||
|
(blockNumber: 0'u64, id: (crc: 0xa3f5ab08'u32, nextFork: 1561651'u64)), # Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||||
|
(blockNumber: 1561650'u64, id: (crc: 0xa3f5ab08'u32, nextFork: 1561651'u64)), # Last Petersburg block
|
||||||
|
(blockNumber: 1561651'u64, id: (crc: 0xc25efa5c'u32, nextFork: 0'u64)), # First Istanbul block
|
||||||
|
(blockNumber: 2000000'u64, id: (crc: 0xc25efa5c'u32, nextFork: 0'u64)), # Future Istanbul block
|
||||||
|
]
|
||||||
|
|
||||||
|
template runTest(network: PublicNetwork) =
|
||||||
|
test network.astToStr:
|
||||||
|
var
|
||||||
|
memDB = newMemoryDB()
|
||||||
|
chainDB = newBaseChainDB(memDB, true, network)
|
||||||
|
chain = newChain(chainDB)
|
||||||
|
|
||||||
|
for x in `network IDs`:
|
||||||
|
let id = chain.getForkId(x.blockNumber.toBlockNumber)
|
||||||
|
check id.crc == x.id.crc
|
||||||
|
check id.nextFork == x.id.nextFork
|
||||||
|
|
||||||
|
proc forkIdMain*() =
|
||||||
|
suite "Fork ID tests":
|
||||||
|
runTest(MainNet)
|
||||||
|
runTest(RopstenNet)
|
||||||
|
runTest(RinkebyNet)
|
||||||
|
runTest(GoerliNet)
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
forkIdMain()
|
Loading…
Reference in New Issue