Fluffy state bridge updates (#2683)
* Use Json decode when handling portal rpc client error. * Remove preimages cache. * Support disabling state gossip in order to just build state.
This commit is contained in:
parent
a03bb56bec
commit
9192aa13ed
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/strutils,
|
json_serialization,
|
||||||
chronos,
|
chronos,
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
results,
|
results,
|
||||||
|
@ -29,17 +29,26 @@ type
|
||||||
InvalidContentValue
|
InvalidContentValue
|
||||||
ContentValidationFailed
|
ContentValidationFailed
|
||||||
|
|
||||||
|
ErrorResponse = object
|
||||||
|
code*: int
|
||||||
|
message*: string
|
||||||
|
|
||||||
proc init*(T: type PortalRpcClient, rpcClient: RpcClient): T =
|
proc init*(T: type PortalRpcClient, rpcClient: RpcClient): T =
|
||||||
T(rpcClient)
|
T(rpcClient)
|
||||||
|
|
||||||
func toPortalRpcError(e: ref CatchableError): PortalRpcError =
|
func toPortalRpcError(e: ref CatchableError): PortalRpcError =
|
||||||
# TODO: Update this to parse the error message json
|
let error =
|
||||||
if e.msg.contains("-39001"):
|
try:
|
||||||
|
Json.decode(e.msg, ErrorResponse)
|
||||||
|
except SerializationError as e:
|
||||||
|
raiseAssert(e.msg)
|
||||||
|
|
||||||
|
if error.code == -39001:
|
||||||
ContentNotFound
|
ContentNotFound
|
||||||
elif e.msg.contains("-32602"):
|
elif error.code == -32602:
|
||||||
InvalidContentKey
|
InvalidContentKey
|
||||||
else:
|
else:
|
||||||
raiseAssert(e.msg) # Shouldn't happen
|
raiseAssert(e.msg)
|
||||||
|
|
||||||
proc historyLocalContent(
|
proc historyLocalContent(
|
||||||
client: PortalRpcClient, contentKey: string
|
client: PortalRpcClient, contentKey: string
|
||||||
|
|
|
@ -146,11 +146,19 @@ type
|
||||||
.}: uint64
|
.}: uint64
|
||||||
|
|
||||||
verifyStateProofs* {.
|
verifyStateProofs* {.
|
||||||
desc: "Verify state proofs before gossiping them into the portal network",
|
desc:
|
||||||
|
"Verify state proofs before gossiping them into the portal network (Slow: Only used for testing).",
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
name: "verify-state-proofs"
|
name: "verify-state-proofs"
|
||||||
.}: bool
|
.}: bool
|
||||||
|
|
||||||
|
enableGossip* {.
|
||||||
|
desc:
|
||||||
|
"Enable gossipping the state into the portal network. Disable to only build the state without gossiping it.",
|
||||||
|
defaultValue: true,
|
||||||
|
name: "enable-gossip"
|
||||||
|
.}: bool
|
||||||
|
|
||||||
gossipGenesis* {.
|
gossipGenesis* {.
|
||||||
desc:
|
desc:
|
||||||
"Enable gossip of the genesis state into the portal network when starting from block 1",
|
"Enable gossip of the genesis state into the portal network when starting from block 1",
|
||||||
|
|
|
@ -136,6 +136,7 @@ proc runBackfillBuildBlockOffersLoop(
|
||||||
blockDataQueue: AsyncQueue[BlockData],
|
blockDataQueue: AsyncQueue[BlockData],
|
||||||
blockOffersQueue: AsyncQueue[BlockOffersRef],
|
blockOffersQueue: AsyncQueue[BlockOffersRef],
|
||||||
verifyStateProofs: bool,
|
verifyStateProofs: bool,
|
||||||
|
enableGossip: bool,
|
||||||
gossipGenesis: bool,
|
gossipGenesis: bool,
|
||||||
) {.async: (raises: [CancelledError]).} =
|
) {.async: (raises: [CancelledError]).} =
|
||||||
info "Starting state backfill build block offers loop"
|
info "Starting state backfill build block offers loop"
|
||||||
|
@ -163,7 +164,7 @@ proc runBackfillBuildBlockOffersLoop(
|
||||||
raiseAssert(e.msg) # Should never happen
|
raiseAssert(e.msg) # Should never happen
|
||||||
ws.applyGenesisAccounts(genesisAccounts)
|
ws.applyGenesisAccounts(genesisAccounts)
|
||||||
|
|
||||||
if gossipGenesis:
|
if enableGossip and gossipGenesis:
|
||||||
let genesisBlockHash =
|
let genesisBlockHash =
|
||||||
hash32"d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
|
hash32"d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
|
||||||
|
|
||||||
|
@ -213,17 +214,18 @@ proc runBackfillBuildBlockOffersLoop(
|
||||||
if verifyStateProofs:
|
if verifyStateProofs:
|
||||||
worldState.verifyProofs(blockData.parentStateRoot, blockData.stateRoot)
|
worldState.verifyProofs(blockData.parentStateRoot, blockData.stateRoot)
|
||||||
|
|
||||||
var builder = OffersBuilder.init(worldState, blockData.blockHash)
|
if enableGossip:
|
||||||
builder.buildBlockOffers()
|
var builder = OffersBuilder.init(worldState, blockData.blockHash)
|
||||||
|
builder.buildBlockOffers()
|
||||||
|
|
||||||
await blockOffersQueue.addLast(
|
await blockOffersQueue.addLast(
|
||||||
BlockOffersRef(
|
BlockOffersRef(
|
||||||
blockNumber: blockData.blockNumber,
|
blockNumber: blockData.blockNumber,
|
||||||
accountTrieOffers: builder.getAccountTrieOffers(),
|
accountTrieOffers: builder.getAccountTrieOffers(),
|
||||||
contractTrieOffers: builder.getContractTrieOffers(),
|
contractTrieOffers: builder.getContractTrieOffers(),
|
||||||
contractCodeOffers: builder.getContractCodeOffers(),
|
contractCodeOffers: builder.getContractCodeOffers(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
# After commit of the above db transaction which stores the updated account state
|
# After commit of the above db transaction which stores the updated account state
|
||||||
# then we store the last persisted block number in the database so that we can use it
|
# then we store the last persisted block number in the database so that we can use it
|
||||||
|
@ -350,12 +352,20 @@ proc runBackfillMetricsLoop(
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
await sleepAsync(30.seconds)
|
await sleepAsync(30.seconds)
|
||||||
info "Block data queue metrics: ",
|
|
||||||
nextBlockNumber = blockDataQueue[0].blockNumber,
|
if blockDataQueue.len() > 0:
|
||||||
blockDataQueueLen = blockDataQueue.len()
|
info "Block data queue metrics: ",
|
||||||
info "Block offers queue metrics: ",
|
nextBlockNumber = blockDataQueue[0].blockNumber,
|
||||||
nextBlockNumber = blockOffersQueue[0].blockNumber,
|
blockDataQueueLen = blockDataQueue.len()
|
||||||
blockOffersQueueLen = blockOffersQueue.len()
|
else:
|
||||||
|
info "Block data queue metrics: ", blockDataQueueLen = blockDataQueue.len()
|
||||||
|
|
||||||
|
if blockOffersQueue.len() > 0:
|
||||||
|
info "Block offers queue metrics: ",
|
||||||
|
nextBlockNumber = blockOffersQueue[0].blockNumber,
|
||||||
|
blockOffersQueueLen = blockOffersQueue.len()
|
||||||
|
else:
|
||||||
|
info "Block offers queue metrics: ", blockOffersQueueLen = blockOffersQueue.len()
|
||||||
|
|
||||||
proc runState*(config: PortalBridgeConf) =
|
proc runState*(config: PortalBridgeConf) =
|
||||||
let
|
let
|
||||||
|
@ -402,7 +412,8 @@ proc runState*(config: PortalBridgeConf) =
|
||||||
db, blockDataQueue, web3Client, config.startBlockNumber
|
db, blockDataQueue, web3Client, config.startBlockNumber
|
||||||
)
|
)
|
||||||
asyncSpawn runBackfillBuildBlockOffersLoop(
|
asyncSpawn runBackfillBuildBlockOffersLoop(
|
||||||
db, blockDataQueue, blockOffersQueue, config.verifyStateProofs, config.gossipGenesis
|
db, blockDataQueue, blockOffersQueue, config.verifyStateProofs, config.enableGossip,
|
||||||
|
config.gossipGenesis,
|
||||||
)
|
)
|
||||||
|
|
||||||
for workerId in 1 .. config.gossipWorkersCount.int:
|
for workerId in 1 .. config.gossipWorkersCount.int:
|
||||||
|
|
|
@ -22,35 +22,33 @@ type AccountState* = ref object
|
||||||
code: seq[byte]
|
code: seq[byte]
|
||||||
codeUpdated: bool
|
codeUpdated: bool
|
||||||
|
|
||||||
proc init(T: type AccountState, account = newAccount()): T {.inline.} =
|
proc init(T: type AccountState, account = newAccount()): T =
|
||||||
T(account: account, codeUpdated: false)
|
T(account: account, codeUpdated: false)
|
||||||
|
|
||||||
proc getBalance*(accState: AccountState): UInt256 {.inline.} =
|
template getBalance*(accState: AccountState): UInt256 =
|
||||||
accState.account.balance
|
accState.account.balance
|
||||||
|
|
||||||
proc getNonce*(accState: AccountState): AccountNonce {.inline.} =
|
template getNonce*(accState: AccountState): AccountNonce =
|
||||||
accState.account.nonce
|
accState.account.nonce
|
||||||
|
|
||||||
proc setBalance*(accState: var AccountState, balance: UInt256) {.inline.} =
|
template setBalance*(accState: var AccountState, bal: UInt256) =
|
||||||
accState.account.balance = balance
|
accState.account.balance = bal
|
||||||
|
|
||||||
proc addBalance*(accState: var AccountState, balance: UInt256) {.inline.} =
|
template addBalance*(accState: var AccountState, bal: UInt256) =
|
||||||
accState.account.balance += balance
|
accState.account.balance += bal
|
||||||
|
|
||||||
proc setNonce*(accState: var AccountState, nonce: AccountNonce) {.inline.} =
|
template setNonce*(accState: var AccountState, nce: AccountNonce) =
|
||||||
accState.account.nonce = nonce
|
accState.account.nonce = nce
|
||||||
|
|
||||||
proc setStorage*(
|
template setStorage*(accState: var AccountState, slotKey: UInt256, slotValue: UInt256) =
|
||||||
accState: var AccountState, slotKey: UInt256, slotValue: UInt256
|
|
||||||
) {.inline.} =
|
|
||||||
accState.storageUpdates[slotKey] = slotValue
|
accState.storageUpdates[slotKey] = slotValue
|
||||||
|
|
||||||
proc deleteStorage*(accState: var AccountState, slotKey: UInt256) {.inline.} =
|
template deleteStorage*(accState: var AccountState, slotKey: UInt256) =
|
||||||
# setting to zero has the effect of deleting the slot
|
# setting to zero has the effect of deleting the slot
|
||||||
accState.setStorage(slotKey, 0.u256)
|
accState.setStorage(slotKey, 0.u256)
|
||||||
|
|
||||||
proc setCode*(accState: var AccountState, code: seq[byte]) =
|
template setCode*(accState: var AccountState, bytecode: seq[byte]) =
|
||||||
accState.code = code
|
accState.code = bytecode
|
||||||
accState.codeUpdated = true
|
accState.codeUpdated = true
|
||||||
|
|
||||||
# World State definition
|
# World State definition
|
||||||
|
@ -65,7 +63,6 @@ type
|
||||||
storageTries: TableRef[AddressHash, HexaryTrie]
|
storageTries: TableRef[AddressHash, HexaryTrie]
|
||||||
storageDb: TrieDatabaseRef
|
storageDb: TrieDatabaseRef
|
||||||
bytecodeDb: TrieDatabaseRef # maps AddressHash -> seq[byte]
|
bytecodeDb: TrieDatabaseRef # maps AddressHash -> seq[byte]
|
||||||
preimagesDb: TrieDatabaseRef # maps AddressHash -> EthAddress
|
|
||||||
|
|
||||||
proc init*(
|
proc init*(
|
||||||
T: type WorldStateRef, db: DatabaseRef, accountsTrieRoot: KeccakHash = emptyRlpHash
|
T: type WorldStateRef, db: DatabaseRef, accountsTrieRoot: KeccakHash = emptyRlpHash
|
||||||
|
@ -80,35 +77,17 @@ proc init*(
|
||||||
storageTries: newTable[AddressHash, HexaryTrie](),
|
storageTries: newTable[AddressHash, HexaryTrie](),
|
||||||
storageDb: db.getStorageBackend(),
|
storageDb: db.getStorageBackend(),
|
||||||
bytecodeDb: db.getBytecodeBackend(),
|
bytecodeDb: db.getBytecodeBackend(),
|
||||||
preimagesDb: db.getPreimagesBackend(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
proc stateRoot*(state: WorldStateRef): KeccakHash {.inline.} =
|
template stateRoot*(state: WorldStateRef): KeccakHash =
|
||||||
state.accountsTrie.rootHash()
|
state.accountsTrie.rootHash()
|
||||||
|
|
||||||
proc toAccountKey*(address: EthAddress): AddressHash {.inline.} =
|
template toAccountKey*(address: EthAddress): AddressHash =
|
||||||
keccakHash(address)
|
keccakHash(address)
|
||||||
|
|
||||||
proc toStorageKey*(slotKey: UInt256): SlotKeyHash {.inline.} =
|
template toStorageKey*(slotKey: UInt256): SlotKeyHash =
|
||||||
keccakHash(toBytesBE(slotKey))
|
keccakHash(toBytesBE(slotKey))
|
||||||
|
|
||||||
proc getAccountPreimage(state: WorldStateRef, accountKey: AddressHash): EthAddress =
|
|
||||||
doAssert(
|
|
||||||
state.preimagesDb.contains(rlp.encode(accountKey)),
|
|
||||||
"No account preimage with address hash: " & $accountKey,
|
|
||||||
)
|
|
||||||
let addressBytes = state.preimagesDb.get(rlp.encode(accountKey))
|
|
||||||
|
|
||||||
try:
|
|
||||||
rlp.decode(addressBytes, EthAddress)
|
|
||||||
except RlpError as e:
|
|
||||||
raiseAssert(e.msg) # Should never happen
|
|
||||||
|
|
||||||
proc setAccountPreimage(
|
|
||||||
state: WorldStateRef, accountKey: AddressHash, address: EthAddress
|
|
||||||
) =
|
|
||||||
state.preimagesDb.put(rlp.encode(accountKey), rlp.encode(address))
|
|
||||||
|
|
||||||
proc getAccount(state: WorldStateRef, accountKey: AddressHash): AccountState =
|
proc getAccount(state: WorldStateRef, accountKey: AddressHash): AccountState =
|
||||||
try:
|
try:
|
||||||
if state.accountsTrie.contains(accountKey.data):
|
if state.accountsTrie.contains(accountKey.data):
|
||||||
|
@ -119,12 +98,11 @@ proc getAccount(state: WorldStateRef, accountKey: AddressHash): AccountState =
|
||||||
except RlpError as e:
|
except RlpError as e:
|
||||||
raiseAssert(e.msg) # should never happen unless the database is corrupted
|
raiseAssert(e.msg) # should never happen unless the database is corrupted
|
||||||
|
|
||||||
proc getAccount*(state: WorldStateRef, address: EthAddress): AccountState {.inline.} =
|
template getAccount*(state: WorldStateRef, address: EthAddress): AccountState =
|
||||||
state.getAccount(toAccountKey(address))
|
state.getAccount(toAccountKey(address))
|
||||||
|
|
||||||
proc setAccount*(state: WorldStateRef, address: EthAddress, accState: AccountState) =
|
proc setAccount*(state: WorldStateRef, address: EthAddress, accState: AccountState) =
|
||||||
let accountKey = toAccountKey(address)
|
let accountKey = toAccountKey(address)
|
||||||
state.setAccountPreimage(accountKey, address)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not state.storageTries.contains(accountKey):
|
if not state.storageTries.contains(accountKey):
|
||||||
|
@ -198,12 +176,10 @@ iterator updatedStorageProofs*(
|
||||||
except RlpError as e:
|
except RlpError as e:
|
||||||
raiseAssert(e.msg) # should never happen unless the database is corrupted
|
raiseAssert(e.msg) # should never happen unless the database is corrupted
|
||||||
|
|
||||||
proc getUpdatedBytecode*(
|
template getUpdatedBytecode*(state: WorldStateRef, accountKey: AddressHash): seq[byte] =
|
||||||
state: WorldStateRef, accountKey: AddressHash
|
|
||||||
): seq[byte] {.inline.} =
|
|
||||||
state.db.getBytecodeUpdatedCache().get(accountKey.data)
|
state.db.getBytecodeUpdatedCache().get(accountKey.data)
|
||||||
|
|
||||||
# Slow: Used for testing only
|
# Slow: Only used for testing
|
||||||
proc verifyProofs*(
|
proc verifyProofs*(
|
||||||
state: WorldStateRef, preStateRoot: KeccakHash, expectedStateRoot: KeccakHash
|
state: WorldStateRef, preStateRoot: KeccakHash, expectedStateRoot: KeccakHash
|
||||||
) =
|
) =
|
||||||
|
|
Loading…
Reference in New Issue