Skip to content

Commit ba8437d

Browse files
committed
state: implement solution for receive / gossip account trie nodes
1 parent a2170ff commit ba8437d

File tree

1 file changed

+58
-3
lines changed
  • packages/portalnetwork/src/networks/state

1 file changed

+58
-3
lines changed

packages/portalnetwork/src/networks/state/state.ts

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { ENR } from '@chainsafe/discv5'
1+
import { ENR, distance } from '@chainsafe/discv5'
22
import { fromHexString, toHexString } from '@chainsafe/ssz'
3-
import { bytesToInt, hexToBytes } from '@ethereumjs/util'
3+
import { BranchNode, ExtensionNode, Trie, decodeNode } from '@ethereumjs/trie'
4+
import { bytesToHex, bytesToInt, hexToBytes } from '@ethereumjs/util'
45
import debug from 'debug'
56

67
import { shortId } from '../../util/util.js'
@@ -16,7 +17,13 @@ import { BaseNetwork } from '../network.js'
1617
import { NetworkId } from '../types.js'
1718

1819
import { StateDB } from './statedb.js'
19-
import { StateNetworkContentType } from './types.js'
20+
import { AccountTrieNodeOffer, AccountTrieNodeRetrieval, StateNetworkContentType } from './types.js'
21+
import {
22+
AccountTrieNodeContentKey,
23+
StateNetworkContentId,
24+
tightlyPackNibbles,
25+
unpackNibbles,
26+
} from './util.js'
2027

2128
import type { PortalNetwork } from '../../client/client.js'
2229
import type { FindContentMessage } from '../../wire/types.js'
@@ -135,4 +142,52 @@ export class StateNetwork extends BaseNetwork {
135142
this.logger(`content added for: ${contentKey}`)
136143
this.emit('ContentAdded', contentKey, contentType, content)
137144
}
145+
146+
async receiveAccountTrieNodeOffer(contentKey: Uint8Array, content: Uint8Array) {
147+
const { path } = AccountTrieNodeContentKey.decode(contentKey)
148+
const { blockHash, proof } = AccountTrieNodeOffer.deserialize(content)
149+
150+
await this.gossipContent(contentKey, content)
151+
152+
const stateRoot = new Trie({ useKeyHashing: true })['hash'](proof[0])
153+
this.stateDB.storeBlock({ blockHash, stateRoot })
154+
155+
const nibbles = unpackNibbles(path.packedNibbles, path.isOddLength)
156+
const newpaths = [...nibbles]
157+
const nodes = [...proof]
158+
nodes.pop()
159+
const gossipContents: { contentKey: Uint8Array; content: Uint8Array }[] = []
160+
161+
while (nodes.length > 0) {
162+
const rlp = nodes.pop()!
163+
const curNode = decodeNode(rlp)
164+
if (curNode instanceof BranchNode) {
165+
newpaths.pop()
166+
} else if (curNode instanceof ExtensionNode) {
167+
newpaths.splice(-curNode.key().length)
168+
} else {
169+
throw new Error('Should have already removed leaf node from array')
170+
}
171+
const nodeHash = new Trie({ useKeyHashing: true })['hash'](rlp)
172+
const contentKey = AccountTrieNodeContentKey.encode({
173+
nodeHash,
174+
path: tightlyPackNibbles(newpaths),
175+
})
176+
const gossipContent = AccountTrieNodeOffer.serialize({ blockHash, proof: nodes })
177+
gossipContents.push({ contentKey, content: gossipContent })
178+
const contentId = StateNetworkContentId.fromBytes(contentKey)
179+
const in_radius = distance(bytesToHex(contentId), this.enr.nodeId) < this.nodeRadius
180+
if (in_radius) {
181+
const toStore = AccountTrieNodeRetrieval.serialize({
182+
node: rlp,
183+
})
184+
await this.stateDB.storeContent(contentKey, toStore)
185+
}
186+
187+
for (const { content, contentKey } of gossipContents) {
188+
await this.gossipContent(contentKey, content)
189+
}
190+
}
191+
return gossipContents
192+
}
138193
}

0 commit comments

Comments
 (0)