Fluffy state network tests and logging improvements (#2402)

* Improve tests by waiting for content to get into db.

* Improve state network logging.
This commit is contained in:
web3-developer 2024-06-20 23:41:34 +08:00 committed by GitHub
parent bd2ca07da6
commit 09946c9958
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 45 additions and 39 deletions

View File

@ -79,7 +79,7 @@ proc getAccountProof(
while nibblesIdx < nibbles.len(): while nibblesIdx < nibbles.len():
let let
accountTrieNode = (await n.getAccountTrieNode(key)).valueOr: accountTrieNode = (await n.getAccountTrieNode(key)).valueOr:
# log something here warn "Failed to get account trie node when building account proof"
return Opt.none(TrieProof) return Opt.none(TrieProof)
trieNode = accountTrieNode.node trieNode = accountTrieNode.node
@ -106,7 +106,7 @@ proc getStorageProof(
while nibblesIdx < nibbles.len(): while nibblesIdx < nibbles.len():
let let
contractTrieNode = (await n.getContractTrieNode(key)).valueOr: contractTrieNode = (await n.getContractTrieNode(key)).valueOr:
# log something here warn "Failed to get contract trie node when building account proof"
return Opt.none(TrieProof) return Opt.none(TrieProof)
trieNode = contractTrieNode.node trieNode = contractTrieNode.node
@ -131,7 +131,7 @@ proc getAccount(
warn "Failed to get account proof" warn "Failed to get account proof"
return Opt.none(Account) return Opt.none(Account)
account = accountProof.toAccount().valueOr: account = accountProof.toAccount().valueOr:
warn "Failed to get account from accountProof" error "Failed to get account from accountProof"
return Opt.none(Account) return Opt.none(Account)
Opt.some(account) Opt.some(account)
@ -165,7 +165,7 @@ proc getStorageAt*(
warn "Failed to get storage proof" warn "Failed to get storage proof"
return Opt.none(UInt256) return Opt.none(UInt256)
slotValue = storageProof.toSlot().valueOr: slotValue = storageProof.toSlot().valueOr:
warn "Failed to get slot from storageProof" error "Failed to get slot from storageProof"
return Opt.none(UInt256) return Opt.none(UInt256)
Opt.some(slotValue) Opt.some(slotValue)

View File

@ -140,7 +140,7 @@ proc recursiveGossipOffer*(
key: AccountTrieNodeKey, key: AccountTrieNodeKey,
offer: AccountTrieNodeOffer, offer: AccountTrieNodeOffer,
) {.async: (raises: [CancelledError]).} = ) {.async: (raises: [CancelledError]).} =
asyncSpawn gossipOffer(p, srcNodeId, keyBytes, offerBytes, key, offer) await gossipOffer(p, srcNodeId, keyBytes, offerBytes, key, offer)
# root node, recursive gossip is finished # root node, recursive gossip is finished
if key.path.unpackNibbles().len() == 0: if key.path.unpackNibbles().len() == 0:
@ -151,7 +151,7 @@ proc recursiveGossipOffer*(
(parentKey, parentOffer) = offer.withKey(key).getParent() (parentKey, parentOffer) = offer.withKey(key).getParent()
parentKeyBytes = parentKey.toContentKey().encode() parentKeyBytes = parentKey.toContentKey().encode()
asyncSpawn recursiveGossipOffer( await recursiveGossipOffer(
p, srcNodeId, parentKeyBytes, parentOffer.encode(), parentKey, parentOffer p, srcNodeId, parentKeyBytes, parentOffer.encode(), parentKey, parentOffer
) )
@ -165,7 +165,7 @@ proc recursiveGossipOffer*(
key: ContractTrieNodeKey, key: ContractTrieNodeKey,
offer: ContractTrieNodeOffer, offer: ContractTrieNodeOffer,
) {.async: (raises: [CancelledError]).} = ) {.async: (raises: [CancelledError]).} =
asyncSpawn gossipOffer(p, srcNodeId, keyBytes, offerBytes, key, offer) await gossipOffer(p, srcNodeId, keyBytes, offerBytes, key, offer)
# root node, recursive gossip is finished # root node, recursive gossip is finished
if key.path.unpackNibbles().len() == 0: if key.path.unpackNibbles().len() == 0:
@ -176,6 +176,6 @@ proc recursiveGossipOffer*(
(parentKey, parentOffer) = offer.withKey(key).getParent() (parentKey, parentOffer) = offer.withKey(key).getParent()
parentKeyBytes = parentKey.toContentKey().encode() parentKeyBytes = parentKey.toContentKey().encode()
asyncSpawn recursiveGossipOffer( await recursiveGossipOffer(
p, srcNodeId, parentKeyBytes, parentOffer.encode(), parentKey, parentOffer p, srcNodeId, parentKeyBytes, parentOffer.encode(), parentKey, parentOffer
) )

View File

@ -86,25 +86,26 @@ proc getContent(
let contentFromDB = n.contentDB.get(contentId) let contentFromDB = n.contentDB.get(contentId)
if contentFromDB.isSome(): if contentFromDB.isSome():
let contentValue = V.decode(contentFromDB.get()).valueOr: let contentValue = V.decode(contentFromDB.get()).valueOr:
error "Unable to decode account trie node content value from database" error "Unable to decode state content value from database"
return Opt.none(V) return Opt.none(V)
info "Fetched account trie node from database" info "Fetched state content value from database"
return Opt.some(contentValue) return Opt.some(contentValue)
let let
contentLookupResult = ( contentLookupResult = (
await n.portalProtocol.contentLookup(contentKeyBytes, contentId) await n.portalProtocol.contentLookup(contentKeyBytes, contentId)
).valueOr: ).valueOr:
warn "Failed fetching state content from the network"
return Opt.none(V) return Opt.none(V)
contentValueBytes = contentLookupResult.content contentValueBytes = contentLookupResult.content
let contentValue = V.decode(contentValueBytes).valueOr: let contentValue = V.decode(contentValueBytes).valueOr:
error "Unable to decode account trie node content value from content lookup" warn "Unable to decode state content value from content lookup"
return Opt.none(V) return Opt.none(V)
validateRetrieval(key, contentValue).isOkOr: validateRetrieval(key, contentValue).isOkOr:
error "Validation of retrieved content failed" warn "Validation of retrieved state content failed"
return Opt.none(V) return Opt.none(V)
n.portalProtocol.storeContent(contentKeyBytes, contentId, contentValueBytes) n.portalProtocol.storeContent(contentKeyBytes, contentId, contentValueBytes)
@ -134,7 +135,7 @@ proc getStateRootByBlockHash*(
n: StateNetwork, hash: BlockHash n: StateNetwork, hash: BlockHash
): Future[Opt[KeccakHash]] {.async: (raises: [CancelledError]).} = ): Future[Opt[KeccakHash]] {.async: (raises: [CancelledError]).} =
if n.historyNetwork.isNone(): if n.historyNetwork.isNone():
warn "History network is not available. Unable to get state root by block hash" warn "History network is not available"
return Opt.none(KeccakHash) return Opt.none(KeccakHash)
let header = (await n.historyNetwork.get().getVerifiedBlockHeader(hash)).valueOr: let header = (await n.historyNetwork.get().getVerifiedBlockHeader(hash)).valueOr:
@ -174,7 +175,7 @@ proc processOffer*(
) )
info "Offered content validated successfully", contentKeyBytes info "Offered content validated successfully", contentKeyBytes
asyncSpawn gossipOffer( await gossipOffer(
n.portalProtocol, maybeSrcNodeId, contentKeyBytes, contentValueBytes, contentKey, n.portalProtocol, maybeSrcNodeId, contentKeyBytes, contentValueBytes, contentKey,
contentValue, contentValue,
) )

View File

@ -33,6 +33,7 @@ proc isValidNextNode(
nextNode.hashEquals(nextHash) nextNode.hashEquals(nextHash)
# TODO: Refactor this function to improve maintainability
proc validateTrieProof*( proc validateTrieProof*(
expectedRootHash: Opt[KeccakHash], expectedRootHash: Opt[KeccakHash],
path: Nibbles, path: Nibbles,

View File

@ -167,7 +167,7 @@ proc stop*(sn: StateNode) {.async.} =
sn.stateNetwork.stop() sn.stateNetwork.stop()
await sn.discoveryProtocol.closeWait() await sn.discoveryProtocol.closeWait()
proc containsId*(sn: StateNode, contentId: ContentId): bool = proc containsId*(sn: StateNode, contentId: ContentId): bool {.inline.} =
return sn.stateNetwork.contentDB.get(contentId).isSome() return sn.stateNetwork.contentDB.get(contentId).isSome()
proc mockBlockHashToStateRoot*( proc mockBlockHashToStateRoot*(
@ -187,3 +187,11 @@ proc mockBlockHashToStateRoot*(
sn.portalProtocol().storeContent( sn.portalProtocol().storeContent(
contentKeyBytes, contentId, SSZ.encode(blockHeaderWithProof) contentKeyBytes, contentId, SSZ.encode(blockHeaderWithProof)
) )
proc waitUntilContentAvailable*(sn: StateNode, contentId: ContentId) {.async.} =
var waitCount = 0
while not sn.containsId(contentId):
await sleepAsync(10.milliseconds)
inc waitCount
if waitCount > 1000:
break

View File

@ -71,7 +71,9 @@ procSuite "State Endpoints":
) )
# wait for recursive gossip to complete # wait for recursive gossip to complete
await sleepAsync(2000.milliseconds) for node in testData.recursive_gossip:
let keyBytes = node.content_key.hexToSeqByte().ByteList
await stateNode2.waitUntilContentAvailable(toContentId(keyBytes))
let let
address = address =
@ -201,7 +203,9 @@ procSuite "State Endpoints":
) )
# wait for recursive gossip to complete # wait for recursive gossip to complete
await sleepAsync(1000.milliseconds) for node in testData.recursive_gossip:
let keyBytes = node.content_key.hexToSeqByte().ByteList
await stateNode2.waitUntilContentAvailable(toContentId(keyBytes))
let let
address = EthAddress.fromHex("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") address = EthAddress.fromHex("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
@ -246,8 +250,8 @@ procSuite "State Endpoints":
contentValue, contentValue,
) )
# wait for recursive gossip to complete # wait for gossip to complete
await sleepAsync(1000.milliseconds) await stateNode2.waitUntilContentAvailable(contentId)
let let
address = EthAddress.fromHex("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") address = EthAddress.fromHex("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")

View File

@ -76,9 +76,7 @@ procSuite "State Gossip - Gossip Offer":
) )
# wait for offer to be processed by state node 2 # wait for offer to be processed by state node 2
while not stateNode2.stateNetwork.contentQueue.empty(): await stateNode2.waitUntilContentAvailable(contentId)
await sleepAsync(1.milliseconds)
await sleepAsync(100.milliseconds)
# check that the offer was received by the second state instance # check that the offer was received by the second state instance
let res1 = let res1 =
@ -151,9 +149,7 @@ procSuite "State Gossip - Gossip Offer":
) )
# wait for offer to be processed by state node 2 # wait for offer to be processed by state node 2
while not stateNode2.stateNetwork.contentQueue.empty(): await stateNode2.waitUntilContentAvailable(contentId)
await sleepAsync(1.milliseconds)
await sleepAsync(100.milliseconds)
# check that the offer was received by the second state instance # check that the offer was received by the second state instance
let res1 = await stateNode2.stateNetwork.getContractTrieNode( let res1 = await stateNode2.stateNetwork.getContractTrieNode(
@ -216,9 +212,7 @@ procSuite "State Gossip - Gossip Offer":
) )
# wait for offer to be processed by state node 2 # wait for offer to be processed by state node 2
while not stateNode2.stateNetwork.contentQueue.empty(): await stateNode2.waitUntilContentAvailable(contentId)
await sleepAsync(1.milliseconds)
await sleepAsync(100.milliseconds)
# check that the offer was received by the second state instance # check that the offer was received by the second state instance
let res1 = let res1 =
@ -280,7 +274,9 @@ procSuite "State Gossip - Gossip Offer":
) )
# wait for recursive gossip to complete # wait for recursive gossip to complete
await sleepAsync(1000.milliseconds) for node in testData.recursive_gossip:
let keyBytes = node.content_key.hexToSeqByte().ByteList
await stateNode2.waitUntilContentAvailable(toContentId(keyBytes))
# check that all nodes were received by both state instances # check that all nodes were received by both state instances
for kv in testData.recursive_gossip: for kv in testData.recursive_gossip:
@ -357,7 +353,9 @@ procSuite "State Gossip - Gossip Offer":
) )
# wait for recursive gossip to complete # wait for recursive gossip to complete
await sleepAsync(1000.milliseconds) for node in testData.recursive_gossip:
let keyBytes = node.content_key.hexToSeqByte().ByteList
await stateNode2.waitUntilContentAvailable(toContentId(keyBytes))
# check that all nodes were received by both state instances # check that all nodes were received by both state instances
for kv in testData.recursive_gossip: for kv in testData.recursive_gossip:

View File

@ -271,9 +271,7 @@ procSuite "State Network - Offer Content":
check offerResult.isOk() check offerResult.isOk()
# wait for offer to be processed by state node 2 # wait for offer to be processed by state node 2
while not stateNode2.stateNetwork.contentQueue.empty(): await stateNode2.waitUntilContentAvailable(contentId)
await sleepAsync(1.milliseconds)
await sleepAsync(100.milliseconds)
let getRes = let getRes =
await stateNode2.stateNetwork.getAccountTrieNode(contentKey.accountTrieNodeKey) await stateNode2.stateNetwork.getAccountTrieNode(contentKey.accountTrieNodeKey)
@ -322,9 +320,7 @@ procSuite "State Network - Offer Content":
check offerResult.isOk() check offerResult.isOk()
# wait for offer to be processed by state node 2 # wait for offer to be processed by state node 2
while not stateNode2.stateNetwork.contentQueue.empty(): await stateNode2.waitUntilContentAvailable(contentId)
await sleepAsync(1.milliseconds)
await sleepAsync(100.milliseconds)
let getRes = await stateNode2.stateNetwork.getContractTrieNode( let getRes = await stateNode2.stateNetwork.getContractTrieNode(
contentKey.contractTrieNodeKey contentKey.contractTrieNodeKey
@ -374,9 +370,7 @@ procSuite "State Network - Offer Content":
check offerResult.isOk() check offerResult.isOk()
# wait for offer to be processed by state node 2 # wait for offer to be processed by state node 2
while not stateNode2.stateNetwork.contentQueue.empty(): await stateNode2.waitUntilContentAvailable(contentId)
await sleepAsync(1.milliseconds)
await sleepAsync(100.milliseconds)
let getRes = let getRes =
await stateNode2.stateNetwork.getContractCode(contentKey.contractCodeKey) await stateNode2.stateNetwork.getContractCode(contentKey.contractCodeKey)