-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduction of P2P networking #666
Conversation
…ges into pw/big-branch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got up to yarn-project/aztec-node/src/aztec-node/http-node.ts
, will continue with the rest on Monday. Looking awesome so far. I like that you also tackled the problems that arise from having to identify the source of unverified data due to having multiple sequencers.
- noir-contracts: *yarn_project | ||
- noir-compiler: *yarn_project | ||
- sequencer-client: *yarn_project | ||
- types: *yarn_project | ||
- circuits-js: *yarn_project | ||
- rollup-provider: *yarn_project | ||
|
||
- e2e-join: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the new jobs to e2e-join requirements, so all unit tests finish before we start the e2e ones
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed that, thanks
sender: EthAddress.random().toString(), | ||
l2BlockNum: BigInt(l2Block.number), | ||
l2BlockHash: `0x${l2Block.getCalldataHash().toString('hex')}`, | ||
sender: EthAddress.random(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sender: EthAddress.random(), | |
sender: EthAddress.random().toString(), |
This should let you remove the nasty as unknown
in the cast. See #648.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, done.
transactionHash: `0x${l2BlockNum}`, | ||
} as Log<bigint, number, undefined, typeof UnverifiedDataEmitterAbi, 'ContractDeployment'>; | ||
transactionHash: `0x${l2Block.number}`, | ||
} as unknown as Log<bigint, number, undefined, typeof UnverifiedDataEmitterAbi, 'ContractDeployment'>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try removing here as well
@@ -37,5 +49,7 @@ export function getConfigEnvVars(): ArchiverConfig { | |||
unverifiedDataEmitterContract: UNVERIFIED_DATA_EMITTER_ADDRESS | |||
? EthAddress.fromString(UNVERIFIED_DATA_EMITTER_ADDRESS) | |||
: EthAddress.ZERO, | |||
searchStartBlock: SEARCH_START_BLOCK ? +SEARCH_START_BLOCK : 0, | |||
apiKey: API_KEY || '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd avoid using empty strings to signal empty values. Let's change apiKey
to be string | undefined
if it could be unset.
@@ -123,20 +130,28 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa | |||
this.nextL2BlockFromBlock, | |||
nextExpectedRollupId, | |||
); | |||
|
|||
// create the block number -> block hash mapping to ensure we retrieve the appropriate events | |||
const blockHashMapping: { [key: string]: Buffer } = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const blockHashMapping: { [key: string]: Buffer } = {}; | |
const blockHashMapping: { [key: string]: Buffer | undefined } = {}; |
So the compiler forces you to check that a given key is in the mapping before trying to use it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's import the artifact from noir-contracts
instead of copying it here manually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, that change is already done. Removed the legacy file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this copied from end-to-end/src/deploy_l1_contracts.ts
? If so, let's delete it from there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is. In Aztec Connect we had a blockchain
package which handled everything. Environment config, contract wrappers, chain scanning and event parsing, publishing, contract deployment scripts etc. In Aztec 3 everything is scattered. So the archiver has code for block scanning, sequencer-client has the block publishing etc. I'm wondering if we want to re-instate blockchain
as a place for common chain operations/config. I could move environment
into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, moved contract deployment code to common blockchain
package.
export function txToJson(tx: Tx) { | ||
return { | ||
data: tx.data?.toBuffer().toString('hex'), | ||
unverified: tx.unverifiedData?.toBuffer().toString('hex'), | ||
txRequest: tx.txRequest?.toBuffer().toString('hex'), | ||
proof: tx.proof?.toBuffer().toString('hex'), | ||
newContractPublicFunctions: tx.newContractPublicFunctions?.map(f => f.toBuffer().toString('hex')) ?? [], | ||
enqueuedPublicFunctions: tx.enqueuedPublicFunctionCalls?.map(f => f.toBuffer().toString('hex')) ?? [], | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can pass in a custom serializer object rather than manually converting every buffer to string. See the implementation of toFriendlyJSON
for an example.
And aside from that, why not use the serialization methods we already have, and push everything over the wire as binary data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just used strings for ease of debugging. Being able to get legible output by cURLing the endpoints is pretty useful. We probably want to change this for at least some endpoints for a production system.
* @param json - The JSON representation of the transaction. | ||
* @returns The deserialised transaction. | ||
*/ | ||
export function txFromJson(json: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, you can pass a reviver to JSON.parse to make your life easier.
return message.subarray(4); | ||
} | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created these serialisation functions as we didn't have anything for Tx
objects. Could possibly just become toBuffer
and fromBuffer
on Tx
. Would prefer to use the existing serialisation but we would need to handle undefined properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but we would need to handle undefined properties.
We could probably introduce a Maybe
or Optional
wrapper that just writes down an initial byte to indicate if the value is set or not, similar to how the Vector
class writes the size first.
However, since we're moving to msgpack now, maybe it makes sense to do things the msgpack way instead? We may want to loop in @ludamad here.
yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave this a power read but everything looks great, nothing much to add ontop of santaigos points / just got a couple of nits, (maybe something around the deepcopy, seems we could make a generic function for that)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM at a powerglance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hell of a PR! 🚀
// shutdown all nodes. | ||
for (const context of contexts) { | ||
await context.node.stop(); | ||
await context.rpcServer.stop(); | ||
} | ||
await bootstrapNode.stop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider moving to an afterEach block, so it runs even if the test fails
// now ensure that all txs were successfully mined | ||
for (const context of contexts) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to also assert that the current "view" of the world state is the same for all nodes?
p2p-bootstrap: | ||
image: aztecprotocol/p2p-bootstrap:latest | ||
ports: | ||
- '40400:40400' | ||
command: 'start' | ||
environment: | ||
DEBUG: 'aztec:*' | ||
P2P_TCP_LISTEN_PORT: 40400 | ||
P2P_TCP_LISTEN_IP: '0.0.0.0' | ||
P2P_ANNOUNCE_HOSTNAME: 'p2p-bootstrap' | ||
PEER_ID_PRIVATE_KEY: '0a260024080112205ea53185db2e52dae74d0d4d6cadc494174810d0a713cd09b0ac517c38bc781e1224080112205ea53185db2e52dae74d0d4d6cadc494174810d0a713cd09b0ac517c38bc781e1a44080112402df8b977f356c6e34fa021c9647973234dff4df706c185794405aafb556723cf5ea53185db2e52dae74d0d4d6cadc494174810d0a713cd09b0ac517c38bc781e' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used? I saw a createBootstrap
in the e2e test that hints that a different bootstrap node is created in the same process as the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't currently used. I had a vision of running the bootstrap node and the test as different containers but the build system isn't setup to publish the images. Everything has to run inside of e2e. I left this here in case I get time to take another look.
return { | ||
chainInfo: foundry, | ||
rpcUrl, | ||
} as EthereumChain; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid as
, since it hides type errors. It's better to set the expected return type in the function declaration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return { | ||
chainInfo: chain, | ||
rpcUrl: chain.rpcUrls.default.http[0], | ||
} as EthereumChain; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return message.subarray(4); | ||
} | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but we would need to handle undefined properties.
We could probably introduce a Maybe
or Optional
wrapper that just writes down an initial byte to indicate if the value is set or not, similar to how the Vector
class writes the size first.
However, since we're moving to msgpack now, maybe it makes sense to do things the msgpack way instead? We may want to loop in @ludamad here.
const postData = JSON.parse((await stream.readAll()) as string); | ||
const tx = txFromJson(postData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to put in some validation here, to make sure we're not passing in garbage within a tx
@@ -35,7 +38,8 @@ export function getConfigEnvVars(): SequencerClientConfig { | |||
unverifiedDataEmitterContract: UNVERIFIED_DATA_EMITTER_ADDRESS | |||
? EthAddress.fromString(UNVERIFIED_DATA_EMITTER_ADDRESS) | |||
: EthAddress.ZERO, | |||
publisherPrivateKey: Buffer.from(SEQ_PUBLISHER_PRIVATE_KEY || ''), | |||
publisherPrivateKey: Buffer.from(SEQ_PUBLISHER_PRIVATE_KEY || '', 'hex'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch
@@ -272,7 +289,7 @@ export class L1Publisher implements L2BlockReceiver { | |||
try { | |||
return await this.txSender.getTransactionReceipt(txHash); | |||
} catch (err) { | |||
this.log(`Error getting tx receipt`, err); | |||
//this.log(`Error getting tx receipt`, err); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this for silencing those annoying logs in the e2e tests? If so, can we differentiate between a "receipt not yet available" and an actual error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, can't remember now. I've uncommented it for now.
* @param tx - The transaction to be cloned. | ||
* @returns The cloned transaction. | ||
*/ | ||
static clone(tx: Tx): Tx { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think cloneDeep
could handle this automatically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Description
This PR makes a number of changes all related to introducing basic P2P networking and multi-sequencer operation into the system. The primary changes are:
AztecNode
is now an interface (which it probably should have always been). AztecNodeService is now the concrete implementation created by e2e tests.rollup-provider
package that creates a standalone instance of the AztecNodeService with a simple http interface. The client side to this http interface isHttpNode
.aztec-cli
can be used to generate transactions and submit them to a running instance ofrollup-provider
as well as deploying the current set of rollup contracts to chain.ethereum
package containing configuration and common code for interaction with L1.p2p
package now has the ability to start P2P networking utilising LibP2P. Given the required configuration, theP2PClient
will create a libp2p client and attempt to make contact with abootstrap
node. From there it uses Kademlia to discover other peers.p2p-bootstrap
which contains a standalone 'bootstrap' node service. This is used solely for seeding the peer tables of new joiners to the network. It doesn't take part in transaction gossiping.Checklist: