2018-02-12 16:59:12 +00:00
|
|
|
import strformat, tables, ttmath, state_db, backends / memory_backend
|
|
|
|
|
2018-01-17 12:57:50 +00:00
|
|
|
type
|
|
|
|
BaseChainDB* = ref object
|
2018-02-12 16:59:12 +00:00
|
|
|
db*: MemoryDB
|
2018-01-17 12:57:50 +00:00
|
|
|
# TODO db*: JournalDB
|
|
|
|
|
2018-02-12 16:59:12 +00:00
|
|
|
proc newBaseChainDB*(db: MemoryDB): BaseChainDB =
|
|
|
|
result.db = db
|
2018-01-17 12:57:50 +00:00
|
|
|
|
2018-02-12 16:59:12 +00:00
|
|
|
proc exists*(self: BaseChainDB; key: string): bool =
|
|
|
|
return self.db.exists(key)
|
2018-01-17 12:57:50 +00:00
|
|
|
|
|
|
|
# proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
|
|
|
# if notself.exists(CANONICALHEADHASHDBKEY):
|
|
|
|
# raise newException(CanonicalHeadNotFound,
|
|
|
|
# "No canonical head set for this chain")
|
|
|
|
# return self.getBlockHeaderByHash(self.db.get(CANONICALHEADHASHDBKEY))
|
|
|
|
|
|
|
|
# proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; blockNumber: int): BlockHeader =
|
|
|
|
# ## Returns the block header with the given number in the canonical chain.
|
|
|
|
# ##
|
|
|
|
# ## Raises BlockNotFound if there's no block header with the given number in the
|
|
|
|
# ## canonical chain.
|
|
|
|
# validateUint256(blockNumber)
|
|
|
|
# return self.getBlockHeaderByHash(self.lookupBlockHash(blockNumber))
|
|
|
|
|
|
|
|
# proc getScore*(self: BaseChainDB; blockHash: cstring): int =
|
|
|
|
# return rlp.decode(self.db.get(makeBlockHashToScoreLookupKey(blockHash)))
|
|
|
|
|
|
|
|
# proc setAsCanonicalChainHead*(self: BaseChainDB; header: BlockHeader): void =
|
|
|
|
# ## Sets the header as the canonical chain HEAD.
|
|
|
|
# for h in reversed(self.findCommonAncestor(header)):
|
|
|
|
# self.addBlockNumberToHashLookup(h)
|
|
|
|
# try:
|
|
|
|
# self.getBlockHeaderByHash(header.hash)
|
|
|
|
# except BlockNotFound:
|
|
|
|
# raise newException(ValueError, "Cannot use unknown block hash as canonical head: {}".format(
|
|
|
|
# header.hash))
|
|
|
|
# self.db.set(CANONICALHEADHASHDBKEY, header.hash)
|
|
|
|
|
|
|
|
# iterator findCommonAncestor*(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
|
|
|
# ## Returns the chain leading up from the given header until the first ancestor it has in
|
|
|
|
# ## common with our canonical chain.
|
|
|
|
# var h = header
|
|
|
|
# while true:
|
|
|
|
# yield h
|
|
|
|
# if h.parentHash == GENESISPARENTHASH:
|
|
|
|
# break
|
|
|
|
# try:
|
|
|
|
# var orig = self.getCanonicalBlockHeaderByNumber(h.blockNumber)
|
|
|
|
# except KeyError:
|
|
|
|
# nil
|
|
|
|
# h = self.getBlockHeaderByHash(h.parentHash)
|
|
|
|
|
|
|
|
# proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: cstring): BlockHeader =
|
|
|
|
# ## Returns the requested block header as specified by block hash.
|
|
|
|
# ##
|
|
|
|
# ## Raises BlockNotFound if it is not present in the db.
|
|
|
|
# validateWord(blockHash)
|
|
|
|
# try:
|
|
|
|
# var block = self.db.get(blockHash)
|
|
|
|
# except KeyError:
|
|
|
|
# raise newException(BlockNotFound, "No block with hash {0} found".format(
|
|
|
|
# encodeHex(blockHash)))
|
|
|
|
# return rlp.decode(block)
|
|
|
|
|
|
|
|
# proc headerExists*(self: BaseChainDB; blockHash: cstring): bool =
|
|
|
|
# ## Returns True if the header with the given block hash is in our DB.
|
|
|
|
# return self.db.exists(blockHash)
|
|
|
|
|
|
|
|
# proc lookupBlockHash*(self: BaseChainDB; blockNumber: int): cstring =
|
|
|
|
# ## Return the block hash for the given block number.
|
|
|
|
# validateUint256(blockNumber)
|
|
|
|
# var
|
|
|
|
# numberToHashKey = makeBlockNumberToHashLookupKey(blockNumber)
|
|
|
|
# blockHash = rlp.decode(self.db.get(numberToHashKey))
|
|
|
|
# return blockHash
|
|
|
|
|
|
|
|
# iterator getReceipts*(self: BaseChainDB; header: BlockHeader; receiptClass: typedesc): Receipt =
|
|
|
|
# var receiptDb = HexaryTrie()
|
|
|
|
# for receiptIdx in itertools.count():
|
|
|
|
# var receiptKey = rlp.encode(receiptIdx)
|
|
|
|
# if receiptKey in receiptDb:
|
|
|
|
# var receiptData = receiptDb[receiptKey]
|
|
|
|
# yield rlp.decode(receiptData)
|
|
|
|
# else:
|
|
|
|
# break
|
|
|
|
|
|
|
|
# iterator getBlockTransactions*(self: BaseChainDB; blockHeader: BlockHeader;
|
|
|
|
# transactionClass: typedesc): FrontierTransaction =
|
|
|
|
# var transactionDb = HexaryTrie(self.db)
|
|
|
|
# for transactionIdx in itertools.count():
|
|
|
|
# var transactionKey = rlp.encode(transactionIdx)
|
|
|
|
# if transactionKey in transactionDb:
|
|
|
|
# var transactionData = transactionDb[transactionKey]
|
|
|
|
# yield rlp.decode(transactionData)
|
|
|
|
# else:
|
|
|
|
# break
|
|
|
|
|
|
|
|
# proc addBlockNumberToHashLookup*(self: BaseChainDB; header: BlockHeader): void =
|
|
|
|
# var blockNumberToHashKey = makeBlockNumberToHashLookupKey(header.blockNumber)
|
|
|
|
# self.db.set(blockNumberToHashKey, rlp.encode(header.hash))
|
|
|
|
|
|
|
|
# proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): void =
|
|
|
|
# if header.parentHash != GENESISPARENTHASH and
|
|
|
|
# notself.headerExists(header.parentHash):
|
|
|
|
# raise newException(ParentNotFound, "Cannot persist block header ({}) with unknown parent ({})".format(
|
|
|
|
# encodeHex(header.hash), encodeHex(header.parentHash)))
|
|
|
|
# self.db.set(header.hash, rlp.encode(header))
|
|
|
|
# if header.parentHash == GENESISPARENTHASH:
|
|
|
|
# var score = header.difficulty
|
|
|
|
# else:
|
|
|
|
# score = self.getScore(header.parentHash) + header.difficulty
|
|
|
|
# self.db.set(makeBlockHashToScoreLookupKey(header.hash), rlp.encode(score))
|
|
|
|
# try:
|
|
|
|
# var headScore = self.getScore(self.getCanonicalHead().hash)
|
|
|
|
# except CanonicalHeadNotFound:
|
|
|
|
# self.setAsCanonicalChainHead(header)
|
|
|
|
|
|
|
|
# proc persistBlockToDb*(self: BaseChainDB; block: FrontierBlock): void =
|
|
|
|
# self.persistHeaderToDb(block.header)
|
|
|
|
# var transactionDb = HexaryTrie(self.db)
|
|
|
|
# for i in 0 ..< len(block.transactions):
|
|
|
|
# var indexKey = rlp.encode(i)
|
|
|
|
# transactionDb[indexKey] = rlp.encode(block.transactions[i])
|
|
|
|
# nil
|
|
|
|
# self.db.set(block.header.unclesHash, rlp.encode(block.uncles))
|
|
|
|
|
|
|
|
# proc addTransaction*(self: BaseChainDB; blockHeader: BlockHeader; indexKey: cstring;
|
|
|
|
# transaction: FrontierTransaction): cstring =
|
|
|
|
# var transactionDb = HexaryTrie(self.db)
|
|
|
|
# transactionDb[indexKey] = rlp.encode(transaction)
|
|
|
|
# return transactionDb.rootHash
|
|
|
|
|
|
|
|
# proc addReceipt*(self: BaseChainDB; blockHeader: BlockHeader; indexKey: cstring;
|
|
|
|
# receipt: Receipt): cstring =
|
|
|
|
# var receiptDb = HexaryTrie()
|
|
|
|
# receiptDb[indexKey] = rlp.encode(receipt)
|
|
|
|
# return receiptDb.rootHash
|
|
|
|
|
|
|
|
# proc snapshot*(self: BaseChainDB): UUID =
|
|
|
|
# return self.db.snapshot()
|
|
|
|
|
|
|
|
# proc commit*(self: BaseChainDB; checkpoint: UUID): void =
|
|
|
|
# self.db.commit(checkpoint)
|
|
|
|
|
|
|
|
# proc clear*(self: BaseChainDB): void =
|
|
|
|
# self.db.clear()
|
|
|
|
|
2018-02-12 16:59:12 +00:00
|
|
|
method getStateDb*(self: BaseChainDB; stateRoot: string; readOnly: bool = false): AccountStateDB =
|
|
|
|
return newAccountStateDB(initTable[string, Int256]())
|
2018-01-17 12:57:50 +00:00
|
|
|
|
|
|
|
# var CANONICALHEADHASHDBKEY = cstring"v1:canonical_head_hash"
|