mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
Merge pull request #93 from status-im/genesis
Added genesis initialization
This commit is contained in:
commit
467a9c3d7a
@ -7,8 +7,8 @@
|
|||||||
# This file may not be copied, modified, or distributed except according to
|
# This file may not be copied, modified, or distributed except according to
|
||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import parseopt, strutils
|
import parseopt, strutils, macros
|
||||||
import asyncdispatch2, eth_keys, eth_p2p
|
import asyncdispatch2, eth_keys, eth_p2p, eth_common, chronicles
|
||||||
|
|
||||||
const
|
const
|
||||||
NimbusName* = "Nimbus"
|
NimbusName* = "Nimbus"
|
||||||
@ -94,14 +94,16 @@ type
|
|||||||
flags*: set[RpcFlags] ## RPC flags
|
flags*: set[RpcFlags] ## RPC flags
|
||||||
binds*: seq[TransportAddress] ## RPC bind address
|
binds*: seq[TransportAddress] ## RPC bind address
|
||||||
|
|
||||||
|
PublicNetwork* = enum
|
||||||
|
CustomNet = 0
|
||||||
|
MainNet = 1
|
||||||
|
MordenNet = 2
|
||||||
|
RopstenNet = 3
|
||||||
|
RinkebyNet = 4
|
||||||
|
KovanNet = 42
|
||||||
|
|
||||||
NetworkFlags* = enum
|
NetworkFlags* = enum
|
||||||
## Ethereum network flags
|
## Ethereum network flags
|
||||||
RopstenNet, ## Use test Ropsten network
|
|
||||||
RinkebyNet, ## Use test Rinkeby network
|
|
||||||
MordenNet, ## Use test Morden network
|
|
||||||
KovanNet, ## Use test Kovan network
|
|
||||||
CustomNet, ## Use custom network
|
|
||||||
MainNet, ## Use main network only
|
|
||||||
NoDiscover, ## Peer discovery disabled
|
NoDiscover, ## Peer discovery disabled
|
||||||
V5Discover, ## Dicovery V5 enabled
|
V5Discover, ## Dicovery V5 enabled
|
||||||
|
|
||||||
@ -128,6 +130,22 @@ type
|
|||||||
## Debug configuration object
|
## Debug configuration object
|
||||||
flags*: set[DebugFlags] ## Debug flags
|
flags*: set[DebugFlags] ## Debug flags
|
||||||
|
|
||||||
|
ChainConfig* = object
|
||||||
|
chainId*: uint
|
||||||
|
homesteadBlock*: BlockNumber
|
||||||
|
daoForkBlock*: BlockNumber
|
||||||
|
daoForkSupport*: bool
|
||||||
|
|
||||||
|
# EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
|
||||||
|
eip150Block*: BlockNumber
|
||||||
|
eip150Hash*: Hash256
|
||||||
|
|
||||||
|
eip155Block*: BlockNumber
|
||||||
|
eip158Block*: BlockNumber
|
||||||
|
|
||||||
|
byzantiumBlock*: BlockNumber
|
||||||
|
constantinopleBlock*: BlockNumber
|
||||||
|
|
||||||
NimbusConfiguration* = ref object
|
NimbusConfiguration* = ref object
|
||||||
## Main Nimbus configuration object
|
## Main Nimbus configuration object
|
||||||
rpc*: RpcConfiguration ## JSON-RPC configuration
|
rpc*: RpcConfiguration ## JSON-RPC configuration
|
||||||
@ -138,6 +156,49 @@ var nimbusConfig {.threadvar.}: NimbusConfiguration
|
|||||||
|
|
||||||
proc getConfiguration*(): NimbusConfiguration {.gcsafe.}
|
proc getConfiguration*(): NimbusConfiguration {.gcsafe.}
|
||||||
|
|
||||||
|
proc publicChainConfig*(id: PublicNetwork): ChainConfig =
|
||||||
|
result = case id
|
||||||
|
of MainNet:
|
||||||
|
ChainConfig(
|
||||||
|
chainId: MainNet.uint,
|
||||||
|
homesteadBlock: 1150000.u256,
|
||||||
|
daoForkBlock: 1920000.u256,
|
||||||
|
daoForkSupport: true,
|
||||||
|
eip150Block: 2463000.u256,
|
||||||
|
eip150Hash: toDigest("2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
|
||||||
|
eip155Block: 2675000.u256,
|
||||||
|
eip158Block: 2675000.u256,
|
||||||
|
byzantiumBlock: 4370000.u256
|
||||||
|
)
|
||||||
|
of RopstenNet:
|
||||||
|
ChainConfig(
|
||||||
|
chainId: RopstenNet.uint,
|
||||||
|
homesteadBlock: 0.u256,
|
||||||
|
daoForkSupport: true,
|
||||||
|
eip150Block: 0.u256,
|
||||||
|
eip150Hash: toDigest("41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
|
||||||
|
eip155Block: 10.u256,
|
||||||
|
eip158Block: 10.u256,
|
||||||
|
byzantiumBlock: 1700000.u256
|
||||||
|
)
|
||||||
|
of RinkebyNet:
|
||||||
|
ChainConfig(
|
||||||
|
chainId: RinkebyNet.uint,
|
||||||
|
homesteadBlock: 1.u256,
|
||||||
|
daoForkSupport: true,
|
||||||
|
eip150Block: 2.u256,
|
||||||
|
eip150Hash: toDigest("9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
|
||||||
|
eip155Block: 3.u256,
|
||||||
|
eip158Block: 3.u256,
|
||||||
|
byzantiumBlock: 1035301.u256
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
error "No chain config for public network", networkId = id
|
||||||
|
doAssert(false, "No chain config for " & $id)
|
||||||
|
ChainConfig()
|
||||||
|
|
||||||
|
result.chainId = uint(id)
|
||||||
|
|
||||||
proc processList(v: string, o: var seq[string]) =
|
proc processList(v: string, o: var seq[string]) =
|
||||||
## Process comma-separated list of strings.
|
## Process comma-separated list of strings.
|
||||||
if len(v) > 0:
|
if len(v) > 0:
|
||||||
@ -243,42 +304,46 @@ proc processRpcArguments(key, value: string): ConfigStatus =
|
|||||||
else:
|
else:
|
||||||
result = EmptyOption
|
result = EmptyOption
|
||||||
|
|
||||||
template setBootnodes(onodes, nodes: untyped): untyped =
|
proc setBootnodes(onodes: var seq[ENode], nodeUris: openarray[string]) =
|
||||||
var node: ENode
|
var node: ENode
|
||||||
for item in (nodes):
|
onodes = newSeqOfCap[ENode](nodeUris.len)
|
||||||
|
for item in nodeUris:
|
||||||
doAssert(processENode(item, node) == Success)
|
doAssert(processENode(item, node) == Success)
|
||||||
(onodes).add(node)
|
onodes.add(node)
|
||||||
|
|
||||||
proc setNetwork(conf: var NetConfiguration, network: NetworkFlags,
|
macro availableEnumValues(T: type enum): untyped =
|
||||||
id: uint = 0) =
|
let impl = getTypeImpl(T)[1].getTypeImpl()
|
||||||
|
result = newNimNode(nnkBracket)
|
||||||
|
for i in 1 ..< impl.len: result.add(newCall("uint", copyNimTree(impl[i])))
|
||||||
|
|
||||||
|
proc toPublicNetwork*(id: uint): PublicNetwork {.inline.} =
|
||||||
|
if id in availableEnumValues(PublicNetwork):
|
||||||
|
result = PublicNetwork(id)
|
||||||
|
|
||||||
|
proc setNetwork(conf: var NetConfiguration, id: PublicNetwork) =
|
||||||
## Set network id and default network bootnodes
|
## Set network id and default network bootnodes
|
||||||
conf.flags.excl({MainNet, MordenNet, RopstenNet, RinkebyNet, KovanNet,
|
conf.networkId = uint(id)
|
||||||
CustomNet})
|
case id
|
||||||
conf.flags.incl(network)
|
|
||||||
assert(not conf.bootNodes.isNil) # Nim bug #7833
|
|
||||||
case network
|
|
||||||
of MainNet:
|
of MainNet:
|
||||||
conf.networkId = uint(1)
|
|
||||||
conf.bootNodes.setLen(0)
|
|
||||||
conf.bootNodes.setBootnodes(MainnetBootnodes)
|
conf.bootNodes.setBootnodes(MainnetBootnodes)
|
||||||
of MordenNet:
|
of MordenNet:
|
||||||
conf.networkId = uint(2)
|
discard
|
||||||
of RopstenNet:
|
of RopstenNet:
|
||||||
conf.networkId = uint(3)
|
|
||||||
conf.bootNodes.setLen(0)
|
|
||||||
conf.bootNodes.setBootnodes(RopstenBootnodes)
|
conf.bootNodes.setBootnodes(RopstenBootnodes)
|
||||||
of RinkebyNet:
|
of RinkebyNet:
|
||||||
conf.networkId = uint(4)
|
|
||||||
conf.bootNodes.setLen(0)
|
|
||||||
conf.bootNodes.setBootnodes(RinkebyBootnodes)
|
conf.bootNodes.setBootnodes(RinkebyBootnodes)
|
||||||
of KovanNet:
|
of KovanNet:
|
||||||
conf.networkId = uint(42)
|
|
||||||
conf.bootNodes.setLen(0)
|
|
||||||
conf.bootNodes.setBootnodes(KovanBootnodes)
|
conf.bootNodes.setBootnodes(KovanBootnodes)
|
||||||
of CustomNet:
|
of CustomNet:
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc setNetwork(conf: var NetConfiguration, id: uint) =
|
||||||
|
## Set network id and default network bootnodes
|
||||||
|
let pubNet = toPublicNetwork(id)
|
||||||
|
if pubNet == CustomNet:
|
||||||
conf.networkId = id
|
conf.networkId = id
|
||||||
else:
|
else:
|
||||||
discard
|
conf.setNetwork(pubNet)
|
||||||
|
|
||||||
proc processNetArguments(key, value: string): ConfigStatus =
|
proc processNetArguments(key, value: string): ConfigStatus =
|
||||||
## Processes only `Networking` related command line options
|
## Processes only `Networking` related command line options
|
||||||
@ -307,24 +372,11 @@ proc processNetArguments(key, value: string): ConfigStatus =
|
|||||||
var res = 0
|
var res = 0
|
||||||
result = processInteger(value, res)
|
result = processInteger(value, res)
|
||||||
if result == Success:
|
if result == Success:
|
||||||
case res
|
config.net.setNetwork(uint(result))
|
||||||
of 1:
|
|
||||||
config.net.setNetwork(MainNet)
|
|
||||||
of 2:
|
|
||||||
config.net.setNetwork(MordenNet)
|
|
||||||
of 3:
|
|
||||||
config.net.setNetwork(RopstenNet)
|
|
||||||
of 4:
|
|
||||||
config.net.setNetwork(RinkebyNet)
|
|
||||||
of 42:
|
|
||||||
config.net.setNetwork(KovanNet)
|
|
||||||
else:
|
|
||||||
config.net.setNetwork(CustomNet, uint(res))
|
|
||||||
elif skey == "nodiscover":
|
elif skey == "nodiscover":
|
||||||
config.net.flags.incl(NoDiscover)
|
config.net.flags.incl(NoDiscover)
|
||||||
elif skey == "v5discover":
|
elif skey == "v5discover":
|
||||||
config.net.flags.incl(V5Discover)
|
config.net.flags.incl(V5Discover)
|
||||||
config.net.bootNodes.setLen(0)
|
|
||||||
config.net.bootNodes.setBootnodes(DiscoveryV5Bootnodes)
|
config.net.bootNodes.setBootnodes(DiscoveryV5Bootnodes)
|
||||||
elif skey == "port":
|
elif skey == "port":
|
||||||
var res = 0
|
var res = 0
|
||||||
@ -403,8 +455,7 @@ proc initConfiguration(): NimbusConfiguration =
|
|||||||
result.rpc.binds = @[initTAddress("127.0.0.1:8545")]
|
result.rpc.binds = @[initTAddress("127.0.0.1:8545")]
|
||||||
|
|
||||||
## Network defaults
|
## Network defaults
|
||||||
result.net.bootNodes = @[] # Nim bug #7833
|
result.net.setNetwork(MainNet)
|
||||||
result.net.setNetwork(RopstenNet)
|
|
||||||
result.net.maxPeers = 25
|
result.net.maxPeers = 25
|
||||||
result.net.maxPendingPeers = 0
|
result.net.maxPendingPeers = 0
|
||||||
result.net.bindPort = 30303'u16
|
result.net.bindPort = 30303'u16
|
||||||
|
@ -30,36 +30,55 @@ proc newBaseChainDB*(db: TrieDatabaseRef): BaseChainDB =
|
|||||||
proc `$`*(db: BaseChainDB): string =
|
proc `$`*(db: BaseChainDB): string =
|
||||||
result = "BaseChainDB"
|
result = "BaseChainDB"
|
||||||
|
|
||||||
proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: Hash256): BlockHeader =
|
proc getBlockHeader*(self: BaseChainDB; blockHash: Hash256, output: var BlockHeader): bool =
|
||||||
## Returns the requested block header as specified by block hash.
|
|
||||||
##
|
|
||||||
## Raises BlockNotFound if it is not present in the db.
|
|
||||||
try:
|
try:
|
||||||
let blk = self.db.get(genericHashKey(blockHash).toOpenArray).toRange
|
let blk = self.db.get(genericHashKey(blockHash).toOpenArray).toRange
|
||||||
return decode(blk, BlockHeader)
|
if blk.len != 0:
|
||||||
|
output = rlp.decode(blk, BlockHeader)
|
||||||
|
result = true
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc getBlockHeader*(self: BaseChainDB, blockHash: Hash256): BlockHeader =
|
||||||
|
## Returns the requested block header as specified by block hash.
|
||||||
|
##
|
||||||
|
## Raises BlockNotFound if it is not present in the db.
|
||||||
|
if not self.getBlockHeader(blockHash, result):
|
||||||
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
||||||
|
|
||||||
proc getHash(self: BaseChainDB, key: DbKey): Hash256 {.inline.} =
|
proc getHash(self: BaseChainDB, key: DbKey, output: var Hash256): bool {.inline.} =
|
||||||
rlp.decode(self.db.get(key.toOpenArray).toRange, Hash256)
|
try:
|
||||||
|
output = rlp.decode(self.db.get(key.toOpenArray).toRange, Hash256)
|
||||||
|
result = true
|
||||||
|
except KeyError:
|
||||||
|
discard
|
||||||
|
|
||||||
proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
||||||
let k = canonicalHeadHashKey()
|
var headHash: Hash256
|
||||||
if k.toOpenArray notin self.db:
|
if not self.getHash(canonicalHeadHashKey(), headHash) or
|
||||||
|
not self.getBlockHeader(headHash, result):
|
||||||
raise newException(CanonicalHeadNotFound,
|
raise newException(CanonicalHeadNotFound,
|
||||||
"No canonical head set for this chain")
|
"No canonical head set for this chain")
|
||||||
return self.getBlockHeaderByHash(self.getHash(k))
|
|
||||||
|
|
||||||
proc lookupBlockHash*(self: BaseChainDB; n: BlockNumber): Hash256 {.inline.} =
|
proc getBlockHash*(self: BaseChainDB, n: BlockNumber, output: var Hash256): bool {.inline.} =
|
||||||
## Return the block hash for the given block number.
|
## Return the block hash for the given block number.
|
||||||
self.getHash(blockNumberToHashKey(n))
|
self.getHash(blockNumberToHashKey(n), output)
|
||||||
|
|
||||||
proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; n: BlockNumber): BlockHeader =
|
proc getBlockHash*(self: BaseChainDB, n: BlockNumber): Hash256 {.inline.} =
|
||||||
## Returns the block header with the given number in the canonical chain.
|
## Return the block hash for the given block number.
|
||||||
##
|
if not self.getHash(blockNumberToHashKey(n), result):
|
||||||
## Raises BlockNotFound if there's no block header with the given number in the
|
raise newException(BlockNotFound, "No block hash for number " & $n)
|
||||||
## canonical chain.
|
|
||||||
self.getBlockHeaderByHash(self.lookupBlockHash(n))
|
proc getBlockHeader*(self: BaseChainDB; n: BlockNumber, output: var BlockHeader): bool =
|
||||||
|
## Returns the block header with the given number in the canonical chain.
|
||||||
|
var blockHash: Hash256
|
||||||
|
if self.getBlockHash(n, blockHash):
|
||||||
|
result = self.getBlockHeader(blockHash, output)
|
||||||
|
|
||||||
|
proc getBlockHeader*(self: BaseChainDB; n: BlockNumber): BlockHeader =
|
||||||
|
## Returns the block header with the given number in the canonical chain.
|
||||||
|
## Raises BlockNotFound error if the block is not in the DB.
|
||||||
|
self.getBlockHeader(self.getBlockHash(n))
|
||||||
|
|
||||||
proc getScore*(self: BaseChainDB; blockHash: Hash256): int =
|
proc getScore*(self: BaseChainDB; blockHash: Hash256): int =
|
||||||
rlp.decode(self.db.get(blockHashToScoreKey(blockHash).toOpenArray).toRange, int)
|
rlp.decode(self.db.get(blockHashToScoreKey(blockHash).toOpenArray).toRange, int)
|
||||||
@ -68,20 +87,17 @@ iterator findNewAncestors(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
|||||||
## Returns the chain leading up from the given header until the first ancestor it has in
|
## Returns the chain leading up from the given header until the first ancestor it has in
|
||||||
## common with our canonical chain.
|
## common with our canonical chain.
|
||||||
var h = header
|
var h = header
|
||||||
|
var orig: BlockHeader
|
||||||
while true:
|
while true:
|
||||||
try:
|
if self.getBlockHeader(h.blockNumber, orig) and orig.hash == h.hash:
|
||||||
let orig = self.getCanonicalBlockHeaderByNumber(h.blockNumber)
|
break
|
||||||
if orig.hash == h.hash:
|
|
||||||
break
|
|
||||||
except BlockNotFound:
|
|
||||||
discard
|
|
||||||
|
|
||||||
yield h
|
yield h
|
||||||
|
|
||||||
if h.parentHash == GENESIS_PARENT_HASH:
|
if h.parentHash == GENESIS_PARENT_HASH:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
h = self.getBlockHeaderByHash(h.parentHash)
|
h = self.getBlockHeader(h.parentHash)
|
||||||
|
|
||||||
proc addBlockNumberToHashLookup(self: BaseChainDB; header: BlockHeader) =
|
proc addBlockNumberToHashLookup(self: BaseChainDB; header: BlockHeader) =
|
||||||
self.db.put(blockNumberToHashKey(header.blockNumber).toOpenArray,
|
self.db.put(blockNumberToHashKey(header.blockNumber).toOpenArray,
|
||||||
@ -104,19 +120,16 @@ proc removeTransactionFromCanonicalChain(self: BaseChainDB, transactionHash: Has
|
|||||||
|
|
||||||
proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockHeader] =
|
proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockHeader] =
|
||||||
## Sets the header as the canonical chain HEAD.
|
## Sets the header as the canonical chain HEAD.
|
||||||
|
let header = self.getBlockHeader(headerHash)
|
||||||
let header = self.getBlockHeaderByHash(headerHash)
|
|
||||||
|
|
||||||
var newCanonicalHeaders = sequtils.toSeq(findNewAncestors(self, header))
|
var newCanonicalHeaders = sequtils.toSeq(findNewAncestors(self, header))
|
||||||
reverse(newCanonicalHeaders)
|
reverse(newCanonicalHeaders)
|
||||||
for h in newCanonicalHeaders:
|
for h in newCanonicalHeaders:
|
||||||
var oldHash: Hash256
|
var oldHash: Hash256
|
||||||
try:
|
if not self.getBlockHash(h.blockNumber, oldHash):
|
||||||
oldHash = self.lookupBlockHash(h.blockNumber)
|
|
||||||
except BlockNotFound:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
let oldHeader = self.getBlockHeaderByHash(oldHash)
|
let oldHeader = self.getBlockHeader(oldHash)
|
||||||
for txHash in self.getBlockTransactionHashes(oldHeader):
|
for txHash in self.getBlockTransactionHashes(oldHeader):
|
||||||
self.removeTransactionFromCanonicalChain(txHash)
|
self.removeTransactionFromCanonicalChain(txHash)
|
||||||
# TODO re-add txn to internal pending pool (only if local sender)
|
# TODO re-add txn to internal pending pool (only if local sender)
|
||||||
@ -171,6 +184,8 @@ proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader
|
|||||||
else: self.getScore(header.parentHash).u256 + header.difficulty
|
else: self.getScore(header.parentHash).u256 + header.difficulty
|
||||||
self.db.put(blockHashToScoreKey(header.hash).toOpenArray, rlp.encode(score).toOpenArray)
|
self.db.put(blockHashToScoreKey(header.hash).toOpenArray, rlp.encode(score).toOpenArray)
|
||||||
|
|
||||||
|
self.addBlockNumberToHashLookup(header)
|
||||||
|
|
||||||
var headScore: int
|
var headScore: int
|
||||||
try:
|
try:
|
||||||
headScore = self.getScore(self.getCanonicalHead().hash)
|
headScore = self.getScore(self.getCanonicalHead().hash)
|
||||||
@ -230,6 +245,41 @@ proc persistBlockToDb*(self: BaseChainDB; blk: Block) =
|
|||||||
proc getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB =
|
proc getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB =
|
||||||
result = newAccountStateDB(self.db, stateRoot)
|
result = newAccountStateDB(self.db, stateRoot)
|
||||||
|
|
||||||
|
method genesisHash*(db: BaseChainDB): KeccakHash =
|
||||||
|
db.getBlockHash(0.toBlockNumber)
|
||||||
|
|
||||||
|
method getBlockHeader*(db: BaseChainDB, b: HashOrNum): BlockHeaderRef =
|
||||||
|
var h: BlockHeader
|
||||||
|
var ok = case b.isHash
|
||||||
|
of true:
|
||||||
|
db.getBlockHeader(b.hash, h)
|
||||||
|
else:
|
||||||
|
db.getBlockHeader(b.number, h)
|
||||||
|
|
||||||
|
if ok:
|
||||||
|
result.new()
|
||||||
|
result[] = h
|
||||||
|
|
||||||
method getBestBlockHeader*(self: BaseChainDB): BlockHeaderRef =
|
method getBestBlockHeader*(self: BaseChainDB): BlockHeaderRef =
|
||||||
result.new()
|
result.new()
|
||||||
result[] = self.getCanonicalHead()
|
result[] = self.getCanonicalHead()
|
||||||
|
|
||||||
|
method getSuccessorHeader*(db: BaseChainDB, h: BlockHeader): BlockHeaderRef =
|
||||||
|
let n = h.blockNumber + 1
|
||||||
|
var r: BlockHeader
|
||||||
|
if db.getBlockHeader(n, r):
|
||||||
|
result.new()
|
||||||
|
result[] = r
|
||||||
|
|
||||||
|
method getBlockBody*(db: BaseChainDB, blockHash: KeccakHash): BlockBodyRef =
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
# Deprecated:
|
||||||
|
proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: Hash256): BlockHeader {.deprecated.} =
|
||||||
|
self.getBlockHeader(blockHash)
|
||||||
|
|
||||||
|
proc lookupBlockHash*(self: BaseChainDB; n: BlockNumber): Hash256 {.deprecated.} =
|
||||||
|
self.getBlockHash(n)
|
||||||
|
|
||||||
|
proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; n: BlockNumber): BlockHeader {.deprecated.} =
|
||||||
|
self.getBlockHeader(n)
|
||||||
|
114
nimbus/genesis.nim
Normal file
114
nimbus/genesis.nim
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import db/[db_chain, state_db], genesis_alloc, eth_common, tables, stint,
|
||||||
|
byteutils, times, config, rlp, ranges, block_types, eth_trie,
|
||||||
|
eth_trie/memdb, constants, nimcrypto, chronicles
|
||||||
|
|
||||||
|
type
|
||||||
|
Genesis* = object
|
||||||
|
config*: ChainConfig
|
||||||
|
nonce*: BlockNonce
|
||||||
|
timestamp*: EthTime
|
||||||
|
extraData*: seq[byte]
|
||||||
|
gasLimit*: GasInt
|
||||||
|
difficulty*: DifficultyInt
|
||||||
|
mixhash*: Hash256
|
||||||
|
coinbase*: EthAddress
|
||||||
|
alloc*: GenesisAlloc
|
||||||
|
|
||||||
|
GenesisAlloc = TableRef[EthAddress, GenesisAccount]
|
||||||
|
GenesisAccount = object
|
||||||
|
code*: seq[byte]
|
||||||
|
storage*: Table[UInt256, UInt256]
|
||||||
|
balance*: UInt256
|
||||||
|
nonce*: UInt256
|
||||||
|
|
||||||
|
func toAddress(n: UInt256): EthAddress =
|
||||||
|
let a = n.toByteArrayBE()
|
||||||
|
result[0 .. ^1] = a.toOpenArray(12, a.high)
|
||||||
|
|
||||||
|
func decodePrealloc(data: seq[byte]): GenesisAlloc =
|
||||||
|
result = newTable[EthAddress, GenesisAccount]()
|
||||||
|
for tup in rlp.decode(data.toRange, seq[(UInt256, UInt256)]):
|
||||||
|
result[toAddress(tup[0])] = GenesisAccount(balance: tup[1])
|
||||||
|
|
||||||
|
proc defaultGenesisBlockForNetwork*(id: PublicNetwork): Genesis =
|
||||||
|
result = case id
|
||||||
|
of MainNet:
|
||||||
|
Genesis(
|
||||||
|
nonce: 66.toBlockNonce,
|
||||||
|
extraData: hexToSeqByte("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
|
||||||
|
gasLimit: 5000,
|
||||||
|
difficulty: 17179869184.u256,
|
||||||
|
alloc: decodePrealloc(mainnetAllocData)
|
||||||
|
)
|
||||||
|
of RopstenNet:
|
||||||
|
Genesis(
|
||||||
|
nonce: 66.toBlockNonce,
|
||||||
|
extraData: hexToSeqByte("0x3535353535353535353535353535353535353535353535353535353535353535"),
|
||||||
|
gasLimit: 16777216,
|
||||||
|
difficulty: 1048576.u256,
|
||||||
|
alloc: decodePrealloc(testnetAllocData)
|
||||||
|
)
|
||||||
|
of RinkebyNet:
|
||||||
|
Genesis(
|
||||||
|
nonce: 66.toBlockNonce,
|
||||||
|
extraData: hexToSeqByte("0x3535353535353535353535353535353535353535353535353535353535353535"),
|
||||||
|
gasLimit: 16777216,
|
||||||
|
difficulty: 1048576.u256,
|
||||||
|
alloc: decodePrealloc(rinkebyAllocData)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# TODO: Fill out the rest
|
||||||
|
error "No default genesis for network", id
|
||||||
|
doAssert(false, "No default genesis for " & $id)
|
||||||
|
Genesis()
|
||||||
|
result.config = publicChainConfig(id)
|
||||||
|
|
||||||
|
proc toBlock*(g: Genesis): BlockHeader =
|
||||||
|
let tdb = trieDB(newMemDB())
|
||||||
|
var trie = initHexaryTrie(tdb)
|
||||||
|
var sdb = newAccountStateDB(tdb, trie.rootHash)
|
||||||
|
|
||||||
|
for address, account in g.alloc:
|
||||||
|
sdb.setBalance(address, account.balance)
|
||||||
|
sdb.setCode(address, account.code.toRange)
|
||||||
|
sdb.setNonce(address, account.nonce)
|
||||||
|
|
||||||
|
for k, v in account.storage:
|
||||||
|
sdb.setStorage(address, k, v)
|
||||||
|
|
||||||
|
var root = sdb.rootHash
|
||||||
|
|
||||||
|
block tempRootHashStub: # TODO: Remove this block when we calculate the root hash correctly
|
||||||
|
if g.config.chainId == 1:
|
||||||
|
const correctMainnetRootHash = toDigest("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544")
|
||||||
|
if root != correctMainnetRootHash:
|
||||||
|
error "Root hash incorrect. Stubbing it out."
|
||||||
|
root = correctMainnetRootHash
|
||||||
|
else:
|
||||||
|
error "Yay! Root hash is correct. Please remove the block where this message comes from."
|
||||||
|
|
||||||
|
result = BlockHeader(
|
||||||
|
nonce: g.nonce,
|
||||||
|
timestamp: g.timestamp,
|
||||||
|
extraData: g.extraData,
|
||||||
|
gasLimit: g.gasLimit,
|
||||||
|
difficulty: g.difficulty,
|
||||||
|
mixDigest: g.mixhash,
|
||||||
|
coinbase: g.coinbase,
|
||||||
|
stateRoot: root,
|
||||||
|
parentHash: GENESIS_PARENT_HASH,
|
||||||
|
txRoot: BLANK_ROOT_HASH,
|
||||||
|
receiptRoot: BLANK_ROOT_HASH,
|
||||||
|
ommersHash: EMPTY_UNCLE_HASH
|
||||||
|
)
|
||||||
|
|
||||||
|
if g.gasLimit == 0:
|
||||||
|
result.gasLimit = GENESIS_GAS_LIMIT
|
||||||
|
|
||||||
|
if g.difficulty == 0:
|
||||||
|
result.difficulty = GENESIS_DIFFICULTY
|
||||||
|
|
||||||
|
proc commit*(g: Genesis, db: BaseChainDB) =
|
||||||
|
let b = g.toBlock()
|
||||||
|
assert(b.blockNumber == 0, "can't commit genesis block with number > 0")
|
||||||
|
discard db.persistHeaderToDb(b)
|
11
nimbus/genesis_alloc.nim
Normal file
11
nimbus/genesis_alloc.nim
Normal file
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@ import
|
|||||||
os, strutils, net, eth_common, db/[storage_types, db_chain],
|
os, strutils, net, eth_common, db/[storage_types, db_chain],
|
||||||
asyncdispatch2, json_rpc/rpcserver, eth_keys,
|
asyncdispatch2, json_rpc/rpcserver, eth_keys,
|
||||||
eth_p2p, eth_p2p/rlpx_protocols/[eth, les],
|
eth_p2p, eth_p2p/rlpx_protocols/[eth, les],
|
||||||
config, rpc/[common, p2p],
|
config, genesis, rpc/[common, p2p],
|
||||||
eth_trie
|
eth_trie
|
||||||
|
|
||||||
const UseSqlite = true
|
const UseSqlite = true
|
||||||
@ -43,10 +43,15 @@ type
|
|||||||
|
|
||||||
proc newTrieDb(): TrieDatabaseRef =
|
proc newTrieDb(): TrieDatabaseRef =
|
||||||
# XXX: Setup db storage location according to config
|
# XXX: Setup db storage location according to config
|
||||||
result = trieDB(newChainDb(":memory:"))
|
result = trieDB(newChainDb("nimbus.db"))
|
||||||
|
|
||||||
proc initializeEmptyDb(db: BaseChainDB) =
|
proc initializeEmptyDb(db: BaseChainDB) =
|
||||||
echo "Initializing empty DB (TODO)"
|
echo "Writing genesis to DB"
|
||||||
|
let networkId = getConfiguration().net.networkId.toPublicNetwork()
|
||||||
|
if networkId == CustomNet:
|
||||||
|
raise newException(Exception, "Custom genesis not implemented")
|
||||||
|
else:
|
||||||
|
defaultGenesisBlockForNetwork(networkId).commit(db)
|
||||||
|
|
||||||
proc start(): NimbusObject =
|
proc start(): NimbusObject =
|
||||||
var nimbus = NimbusObject()
|
var nimbus = NimbusObject()
|
||||||
@ -75,6 +80,7 @@ proc start(): NimbusObject =
|
|||||||
|
|
||||||
if canonicalHeadHashKey().toOpenArray notin trieDB:
|
if canonicalHeadHashKey().toOpenArray notin trieDB:
|
||||||
initializeEmptyDb(chainDb)
|
initializeEmptyDb(chainDb)
|
||||||
|
assert(canonicalHeadHashKey().toOpenArray in trieDB)
|
||||||
|
|
||||||
nimbus.ethNode = newEthereumNode(keypair, address, conf.net.networkId,
|
nimbus.ethNode = newEthereumNode(keypair, address, conf.net.networkId,
|
||||||
nil, nimbusClientId)
|
nil, nimbusClientId)
|
||||||
|
@ -11,7 +11,8 @@ when true:
|
|||||||
./test_memory,
|
./test_memory,
|
||||||
./test_stack,
|
./test_stack,
|
||||||
./test_opcode,
|
./test_opcode,
|
||||||
./test_storage_backends
|
./test_storage_backends,
|
||||||
|
./test_genesis
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
import ./test_vm_json
|
import ./test_vm_json
|
||||||
|
7
tests/test_genesis.nim
Normal file
7
tests/test_genesis.nim
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import unittest, ../nimbus/[genesis, config], eth_common
|
||||||
|
|
||||||
|
suite "Genesis":
|
||||||
|
test "Correct mainnet hash":
|
||||||
|
let g = defaultGenesisBlockForNetwork(MainNet)
|
||||||
|
let b = g.toBlock
|
||||||
|
check(b.blockHash == "D4E56740F876AEF8C010B86A40D5F56745A118D0906A34E69AEC8C0DB1CB8FA3".toDigest)
|
Loading…
x
Reference in New Issue
Block a user