From c58c7dc244fa5010b7de6e04bbe9421a7baaf229 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Fri, 20 Sep 2024 17:09:04 +0100 Subject: [PATCH 01/25] chore: add missing precompiles comments based on interfaces --- precompiles/ArbAggregator.go | 3 +++ precompiles/ArbDebug.go | 4 ++++ precompiles/ArbOwner.go | 11 +++++++++++ precompiles/ArbRetryableTx.go | 4 ++++ 4 files changed, 22 insertions(+) diff --git a/precompiles/ArbAggregator.go b/precompiles/ArbAggregator.go index b74e280fe8..00e6c3d2cc 100644 --- a/precompiles/ArbAggregator.go +++ b/precompiles/ArbAggregator.go @@ -36,6 +36,7 @@ func (con ArbAggregator) GetBatchPosters(c ctx, evm mech) ([]addr, error) { return c.State.L1PricingState().BatchPosterTable().AllPosters(65536) } +// Adds newBatchPoster as a batch poster func (con ArbAggregator) AddBatchPoster(c ctx, evm mech, newBatchPoster addr) error { isOwner, err := c.State.ChainOwners().IsMember(c.caller) if err != nil { @@ -90,12 +91,14 @@ func (con ArbAggregator) SetFeeCollector(c ctx, evm mech, batchPoster addr, newF } // GetTxBaseFee gets an aggregator's current fixed fee to submit a tx +// Deprecated: always returns zero func (con ArbAggregator) GetTxBaseFee(c ctx, evm mech, aggregator addr) (huge, error) { // This is deprecated and now always returns zero. return big.NewInt(0), nil } // SetTxBaseFee sets an aggregator's fixed fee (caller must be the aggregator, its fee collector, or an owner) +// Deprecated: no-op func (con ArbAggregator) SetTxBaseFee(c ctx, evm mech, aggregator addr, feeInL1Gas huge) error { // This is deprecated and is now a no-op. return nil diff --git a/precompiles/ArbDebug.go b/precompiles/ArbDebug.go index bf85d5e18f..60e520da3e 100644 --- a/precompiles/ArbDebug.go +++ b/precompiles/ArbDebug.go @@ -24,6 +24,7 @@ type ArbDebug struct { UnusedError func() error } +// Emits events with values based on the args provided func (con ArbDebug) Events(c ctx, evm mech, paid huge, flag bool, value bytes32) (addr, huge, error) { // Emits 2 events that cover each case // Basic tests an index'd value & a normal value @@ -42,11 +43,13 @@ func (con ArbDebug) Events(c ctx, evm mech, paid huge, flag bool, value bytes32) return c.caller, paid, nil } +// Tries (and fails) to emit logs in a view context func (con ArbDebug) EventsView(c ctx, evm mech) error { _, _, err := con.Events(c, evm, common.Big0, true, bytes32{}) return err } +// Throws a custom error func (con ArbDebug) CustomRevert(c ctx, number uint64) error { return con.CustomError(number, "This spider family wards off bugs: /\\oo/\\ //\\(oo)//\\ /\\oo/\\", true) } @@ -61,6 +64,7 @@ func (con ArbDebug) Panic(c ctx, evm mech) error { panic("called ArbDebug's debug-only Panic method") } +// Throws a hardcoded error func (con ArbDebug) LegacyError(c ctx) error { return errors.New("example legacy error") } diff --git a/precompiles/ArbOwner.go b/precompiles/ArbOwner.go index 8b87445e0e..068c0bf825 100644 --- a/precompiles/ArbOwner.go +++ b/precompiles/ArbOwner.go @@ -120,38 +120,48 @@ func (con ArbOwner) ScheduleArbOSUpgrade(c ctx, evm mech, newVersion uint64, tim return c.State.ScheduleArbOSUpgrade(newVersion, timestamp) } +// Sets equilibration units parameter for L1 price adjustment algorithm func (con ArbOwner) SetL1PricingEquilibrationUnits(c ctx, evm mech, equilibrationUnits huge) error { return c.State.L1PricingState().SetEquilibrationUnits(equilibrationUnits) } +// Sets inertia parameter for L1 price adjustment algorithm func (con ArbOwner) SetL1PricingInertia(c ctx, evm mech, inertia uint64) error { return c.State.L1PricingState().SetInertia(inertia) } +// Sets reward recipient address for L1 price adjustment algorithm func (con ArbOwner) SetL1PricingRewardRecipient(c ctx, evm mech, recipient addr) error { return c.State.L1PricingState().SetPayRewardsTo(recipient) } +// Sets reward amount for L1 price adjustment algorithm, in wei per unit func (con ArbOwner) SetL1PricingRewardRate(c ctx, evm mech, weiPerUnit uint64) error { return c.State.L1PricingState().SetPerUnitReward(weiPerUnit) } +// Set how much ArbOS charges per L1 gas spent on transaction data. func (con ArbOwner) SetL1PricePerUnit(c ctx, evm mech, pricePerUnit *big.Int) error { return c.State.L1PricingState().SetPricePerUnit(pricePerUnit) } +// Sets the base charge (in L1 gas) attributed to each data batch in the calldata pricer func (con ArbOwner) SetPerBatchGasCharge(c ctx, evm mech, cost int64) error { return c.State.L1PricingState().SetPerBatchGasCost(cost) } +// Sets the cost amortization cap in basis points func (con ArbOwner) SetAmortizedCostCapBips(c ctx, evm mech, cap uint64) error { return c.State.L1PricingState().SetAmortizedCostCapBips(cap) } +// Sets the Brotli compression level used for fast compression +// Available in ArbOS version 12 with default level as 1 func (con ArbOwner) SetBrotliCompressionLevel(c ctx, evm mech, level uint64) error { return c.State.SetBrotliCompressionLevel(level) } +// Releases surplus funds from L1PricerFundsPoolAddress for use func (con ArbOwner) ReleaseL1PricerSurplusFunds(c ctx, evm mech, maxWeiToRelease huge) (huge, error) { balance := evm.StateDB.GetBalance(l1pricing.L1PricerFundsPoolAddress) l1p := c.State.L1PricingState() @@ -295,6 +305,7 @@ func (con ArbOwner) RemoveWasmCacheManager(c ctx, _ mech, manager addr) error { return managers.Remove(manager, c.State.ArbOSVersion()) } +// Sets serialized chain config in ArbOS state func (con ArbOwner) SetChainConfig(c ctx, evm mech, serializedChainConfig []byte) error { if c == nil { return errors.New("nil context") diff --git a/precompiles/ArbRetryableTx.go b/precompiles/ArbRetryableTx.go index 93e8023603..7762cc07a8 100644 --- a/precompiles/ArbRetryableTx.go +++ b/precompiles/ArbRetryableTx.go @@ -223,6 +223,9 @@ func (con ArbRetryableTx) Cancel(c ctx, evm mech, ticketId bytes32) error { return con.Canceled(c, evm, ticketId) } +// Gets the redeemer of the current retryable redeem attempt. +// Returns the zero address if the current transaction is not a retryable redeem attempt. +// If this is an auto-redeem, returns the fee refund address of the retryable. func (con ArbRetryableTx) GetCurrentRedeemer(c ctx, evm mech) (common.Address, error) { if c.txProcessor.CurrentRefundTo != nil { return *c.txProcessor.CurrentRefundTo, nil @@ -230,6 +233,7 @@ func (con ArbRetryableTx) GetCurrentRedeemer(c ctx, evm mech) (common.Address, e return common.Address{}, nil } +// Do not call. This method represents a retryable submission to aid explorers. Calling it will always revert. func (con ArbRetryableTx) SubmitRetryable( c ctx, evm mech, requestId bytes32, l1BaseFee, deposit, callvalue, gasFeeCap huge, gasLimit uint64, maxSubmissionFee huge, From ecbe0946b845c97c5d962db5c41703e3271e7b51 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Fri, 18 Oct 2024 10:29:12 -0300 Subject: [PATCH 02/25] Add function to get delay buffer config --- arbnode/delay_buffer.go | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 arbnode/delay_buffer.go diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go new file mode 100644 index 0000000000..5cdfb0edb7 --- /dev/null +++ b/arbnode/delay_buffer.go @@ -0,0 +1,57 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE + +// This file contains functions related to the delay buffer feature that are used mostly in the +// batch poster. + +package arbnode + +import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/offchainlabs/nitro/solgen/go/bridgegen" + "github.com/offchainlabs/nitro/util/headerreader" +) + +// DelayBufferConfig originates from the sequencer inbox contract. +type DelayBufferConfig struct { + Enabled bool + Threshold uint64 +} + +// GetBufferConfig gets the delay buffer config from the sequencer inbox contract. +// If the contract doesn't support the delay buffer, it returns a config with Enabled set to false. +func GetDelayBufferConfig(ctx context.Context, client *ethclient.Client, sequencerInboxAddress common.Address) ( + *DelayBufferConfig, error) { + + sequencerInbox, err := bridgegen.NewSequencerInbox(sequencerInboxAddress, client) + if err != nil { + return nil, fmt.Errorf("create sequencer inbox binding: %w", err) + } + callOpts := bind.CallOpts{ + Context: ctx, + } + enabled, err := sequencerInbox.IsDelayBufferable(&callOpts) + if err != nil { + if headerreader.ExecutionRevertedRegexp.MatchString(err.Error()) { + return &DelayBufferConfig{Enabled: false}, nil + } + return nil, fmt.Errorf("retrieve SequencerInbox.isDelayBufferable: %w", err) + } + if !enabled { + return &DelayBufferConfig{Enabled: false}, nil + } + bufferData, err := sequencerInbox.Buffer(&callOpts) + if err != nil { + return nil, fmt.Errorf("retrieve SequencerInbox.buffer: %w", err) + } + config := &DelayBufferConfig{ + Enabled: true, + Threshold: bufferData.Threshold, + } + return config, nil +} From ef66893d3e991ed42d4915b670f15df424683158 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Fri, 18 Oct 2024 11:24:07 -0300 Subject: [PATCH 03/25] Force batch to avoid consuming the delay buffer --- arbnode/batch_poster.go | 27 ++++++++++++++++++++++++++- arbnode/delay_buffer.go | 8 +------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 46a0160b71..6f546fa0b0 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -720,6 +720,7 @@ type buildingBatch struct { haveUsefulMessage bool use4844 bool muxBackend *simulatedMuxBackend + firstDelayedMsg *arbostypes.MessageWithMetadata firstNonDelayedMsg *arbostypes.MessageWithMetadata firstUsefulMsg *arbostypes.MessageWithMetadata } @@ -1314,7 +1315,11 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) b.building.firstUsefulMsg = msg } } - if !isDelayed && b.building.firstNonDelayedMsg == nil { + if isDelayed { + if b.building.firstDelayedMsg == nil { + b.building.firstDelayedMsg = msg + } + } else if b.building.firstNonDelayedMsg == nil { b.building.firstNonDelayedMsg = msg } b.building.msgCount++ @@ -1329,6 +1334,26 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) } } + delayBuffer, err := GetDelayBufferConfig(ctx, b.seqInbox) + if err != nil { + return false, err + } + if delayBuffer.Enabled && b.building.firstDelayedMsg != nil { + latestHeader, err := b.l1Reader.LastHeader(ctx) + if err != nil { + return false, err + } + latestBlock := latestHeader.Number.Uint64() + firstDelayedMsgBlock := b.building.firstDelayedMsg.Message.Header.BlockNumber + if firstDelayedMsgBlock+delayBuffer.Threshold >= latestBlock { + log.Info("force post batch because of the delay buffer", + "firstDelayedMsgBlock", firstDelayedMsgBlock, + "threshold", delayBuffer.Threshold, + "latestBlock", latestBlock) + forcePostBatch = true + } + } + if b.building.firstNonDelayedMsg != nil && hasL1Bound && config.ReorgResistanceMargin > 0 { firstMsgBlockNumber := b.building.firstNonDelayedMsg.Message.Header.BlockNumber firstMsgTimeStamp := b.building.firstNonDelayedMsg.Message.Header.Timestamp diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go index 5cdfb0edb7..cc62cd716a 100644 --- a/arbnode/delay_buffer.go +++ b/arbnode/delay_buffer.go @@ -11,8 +11,6 @@ import ( "fmt" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util/headerreader" ) @@ -25,13 +23,9 @@ type DelayBufferConfig struct { // GetBufferConfig gets the delay buffer config from the sequencer inbox contract. // If the contract doesn't support the delay buffer, it returns a config with Enabled set to false. -func GetDelayBufferConfig(ctx context.Context, client *ethclient.Client, sequencerInboxAddress common.Address) ( +func GetDelayBufferConfig(ctx context.Context, sequencerInbox *bridgegen.SequencerInbox) ( *DelayBufferConfig, error) { - sequencerInbox, err := bridgegen.NewSequencerInbox(sequencerInboxAddress, client) - if err != nil { - return nil, fmt.Errorf("create sequencer inbox binding: %w", err) - } callOpts := bind.CallOpts{ Context: ctx, } From a05ee98f41f7ed5b111c946033ae145ac0f13219 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 21 Oct 2024 11:30:30 -0300 Subject: [PATCH 04/25] Add delay proof when posting a batch --- arbnode/batch_poster.go | 73 ++++++++++++++++++++++++++++++++++++----- arbnode/delay_buffer.go | 38 +++++++++++++++++++-- 2 files changed, 99 insertions(+), 12 deletions(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 6f546fa0b0..43b22c016e 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -80,8 +80,10 @@ var ( const ( batchPosterSimpleRedisLockKey = "node.batch-poster.redis-lock.simple-lock-key" - sequencerBatchPostMethodName = "addSequencerL2BatchFromOrigin0" - sequencerBatchPostWithBlobsMethodName = "addSequencerL2BatchFromBlobs" + sequencerBatchPostMethodName = "addSequencerL2BatchFromOrigin0" + sequencerBatchPostWithBlobsMethodName = "addSequencerL2BatchFromBlobs" + sequencerBatchPostDelayProofMethodName = "addSequencerL2BatchFromOriginDelayProof" + sequencerBatchPostWithBlobsDelayProofMethodName = "addSequencerL2BatchFromBlobsDelayProof" ) type batchPosterPosition struct { @@ -315,6 +317,7 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e if err = opts.Config().Validate(); err != nil { return nil, err } + // TODO(delaybuffer) use new bridgegen seqInboxABI, err := bridgegen.SequencerInboxMetaData.GetAbi() if err != nil { return nil, err @@ -959,15 +962,25 @@ func (b *BatchPoster) encodeAddBatch( l2MessageData []byte, delayedMsg uint64, use4844 bool, + delayProof *bridgegen.DelayProof, ) ([]byte, []kzg4844.Blob, error) { - methodName := sequencerBatchPostMethodName + var methodName string if use4844 { - methodName = sequencerBatchPostWithBlobsMethodName + if delayProof != nil { + methodName = sequencerBatchPostWithBlobsDelayProofMethodName + } else { + methodName = sequencerBatchPostWithBlobsMethodName + } + } else if delayProof != nil { + methodName = sequencerBatchPostDelayProofMethodName + } else { + methodName = sequencerBatchPostMethodName } method, ok := b.seqInboxABI.Methods[methodName] if !ok { return nil, nil, errors.New("failed to find add batch method") } + var calldata []byte var kzgBlobs []kzg4844.Blob var err error @@ -976,6 +989,9 @@ func (b *BatchPoster) encodeAddBatch( if err != nil { return nil, nil, fmt.Errorf("failed to encode blobs: %w", err) } + } + switch methodName { + case sequencerBatchPostWithBlobsMethodName: // EIP4844 transactions to the sequencer inbox will not use transaction calldata for L2 info. calldata, err = method.Inputs.Pack( seqNum, @@ -984,7 +1000,16 @@ func (b *BatchPoster) encodeAddBatch( new(big.Int).SetUint64(uint64(prevMsgNum)), new(big.Int).SetUint64(uint64(newMsgNum)), ) - } else { + case sequencerBatchPostWithBlobsDelayProofMethodName: + calldata, err = method.Inputs.Pack( + seqNum, + new(big.Int).SetUint64(delayedMsg), + b.config().gasRefunder, + new(big.Int).SetUint64(uint64(prevMsgNum)), + new(big.Int).SetUint64(uint64(newMsgNum)), + delayProof, + ) + case sequencerBatchPostMethodName: calldata, err = method.Inputs.Pack( seqNum, l2MessageData, @@ -993,6 +1018,18 @@ func (b *BatchPoster) encodeAddBatch( new(big.Int).SetUint64(uint64(prevMsgNum)), new(big.Int).SetUint64(uint64(newMsgNum)), ) + case sequencerBatchPostDelayProofMethodName: + calldata, err = method.Inputs.Pack( + seqNum, + l2MessageData, + new(big.Int).SetUint64(delayedMsg), + b.config().gasRefunder, + new(big.Int).SetUint64(uint64(prevMsgNum)), + new(big.Int).SetUint64(uint64(newMsgNum)), + delayProof, + ) + default: + panic("impossible") } if err != nil { return nil, nil, err @@ -1019,7 +1056,17 @@ func estimateGas(client rpc.ClientInterface, ctx context.Context, params estimat return uint64(gas), err } -func (b *BatchPoster) estimateGas(ctx context.Context, sequencerMessage []byte, delayedMessages uint64, realData []byte, realBlobs []kzg4844.Blob, realNonce uint64, realAccessList types.AccessList) (uint64, error) { +func (b *BatchPoster) estimateGas( + ctx context.Context, + sequencerMessage []byte, + delayedMessages uint64, + realData []byte, + realBlobs []kzg4844.Blob, + realNonce uint64, + realAccessList types.AccessList, + delayProof *bridgegen.DelayProof, +) (uint64, error) { + config := b.config() rpcClient := b.l1Reader.Client() rawRpcClient := rpcClient.Client() @@ -1061,7 +1108,7 @@ func (b *BatchPoster) estimateGas(ctx context.Context, sequencerMessage []byte, // However, we set nextMsgNum to 1 because it is necessary for a correct estimation for the final to be non-zero. // Because we're likely estimating against older state, this might not be the actual next message, // but the gas used should be the same. - data, kzgBlobs, err := b.encodeAddBatch(abi.MaxUint256, 0, 1, sequencerMessage, delayedMessages, len(realBlobs) > 0) + data, kzgBlobs, err := b.encodeAddBatch(abi.MaxUint256, 0, 1, sequencerMessage, delayedMessages, len(realBlobs) > 0, delayProof) if err != nil { return 0, err } @@ -1445,7 +1492,15 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) prevMessageCount = 0 } - data, kzgBlobs, err := b.encodeAddBatch(new(big.Int).SetUint64(batchPosition.NextSeqNum), prevMessageCount, b.building.msgCount, sequencerMsg, b.building.segments.delayedMsg, b.building.use4844) + var delayProof *bridgegen.DelayProof + if delayBuffer.Enabled && b.building.firstDelayedMsg != nil { + delayProof, err = GenDelayProof(ctx, b.building.firstDelayedMsg, b.inbox) + if err != nil { + return false, fmt.Errorf("failed to generate delay proof: %w", err) + } + } + + data, kzgBlobs, err := b.encodeAddBatch(new(big.Int).SetUint64(batchPosition.NextSeqNum), prevMessageCount, b.building.msgCount, sequencerMsg, b.building.segments.delayedMsg, b.building.use4844, delayProof) if err != nil { return false, err } @@ -1460,7 +1515,7 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) // In theory, this might reduce gas usage, but only by a factor that's already // accounted for in `config.ExtraBatchGas`, as that same factor can appear if a user // posts a new delayed message that we didn't see while gas estimating. - gasLimit, err := b.estimateGas(ctx, sequencerMsg, lastPotentialMsg.DelayedMessagesRead, data, kzgBlobs, nonce, accessList) + gasLimit, err := b.estimateGas(ctx, sequencerMsg, lastPotentialMsg.DelayedMessagesRead, data, kzgBlobs, nonce, accessList, delayProof) if err != nil { return false, err } diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go index cc62cd716a..c0e317e27c 100644 --- a/arbnode/delay_buffer.go +++ b/arbnode/delay_buffer.go @@ -9,8 +9,12 @@ package arbnode import ( "context" "fmt" + "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util/headerreader" ) @@ -26,9 +30,7 @@ type DelayBufferConfig struct { func GetDelayBufferConfig(ctx context.Context, sequencerInbox *bridgegen.SequencerInbox) ( *DelayBufferConfig, error) { - callOpts := bind.CallOpts{ - Context: ctx, - } + callOpts := bind.CallOpts{Context: ctx} enabled, err := sequencerInbox.IsDelayBufferable(&callOpts) if err != nil { if headerreader.ExecutionRevertedRegexp.MatchString(err.Error()) { @@ -49,3 +51,33 @@ func GetDelayBufferConfig(ctx context.Context, sequencerInbox *bridgegen.Sequenc } return config, nil } + +// GenDelayProof generates the delay proof based on batch's first delayed message and the delayed +// accumulater from the inbox. +func GenDelayProof(ctx context.Context, message *arbostypes.MessageWithMetadata, inbox *InboxTracker) ( + *bridgegen.DelayProof, error) { + + seqNum := message.DelayedMessagesRead + var beforeDelayedAcc common.Hash + if seqNum > 0 { + var err error + beforeDelayedAcc, err = inbox.GetDelayedAcc(seqNum) + if err != nil { + return nil, err + } + } + delayedMessage := bridgegen.MessagesMessage{ + Kind: message.Message.Header.Kind, + Sender: message.Message.Header.Poster, + BlockNumber: message.Message.Header.BlockNumber, + Timestamp: message.Message.Header.Timestamp, + InboxSeqNum: new(big.Int).SetUint64(seqNum), + BaseFeeL1: message.Message.Header.L1BaseFee, + MessageDataHash: crypto.Keccak256Hash(message.Message.L2msg), + } + delayProof := &bridgegen.DelayProof{ + BeforeDelayedAcc: beforeDelayedAcc, + DelayedMessage: delayedMessage, + } + return delayProof, nil +} From d388238dfcfef487a1942f2f56ecd4fb29450022 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 22 Oct 2024 15:52:20 -0300 Subject: [PATCH 05/25] Fix force-batch delay-buffer condition --- arbnode/batch_poster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 43b22c016e..0916aabf00 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -1392,7 +1392,7 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) } latestBlock := latestHeader.Number.Uint64() firstDelayedMsgBlock := b.building.firstDelayedMsg.Message.Header.BlockNumber - if firstDelayedMsgBlock+delayBuffer.Threshold >= latestBlock { + if latestBlock > firstDelayedMsgBlock+delayBuffer.Threshold { log.Info("force post batch because of the delay buffer", "firstDelayedMsgBlock", firstDelayedMsgBlock, "threshold", delayBuffer.Threshold, From 25ef0dcddddf1831ac1ed42578423f9339e1c2a4 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 22 Oct 2024 16:47:08 -0300 Subject: [PATCH 06/25] Support the delay buffer in the deploy pkg --- arbnode/node.go | 11 +++++- cmd/deploy/deploy.go | 9 ++++- deploy/deploy.go | 43 +++++++++++++++--------- system_tests/common_test.go | 17 +++++++++- system_tests/full_challenge_impl_test.go | 1 + 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/arbnode/node.go b/arbnode/node.go index 3613b986ac..d7d9465205 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -53,7 +53,15 @@ import ( "github.com/offchainlabs/nitro/wsbroadcastserver" ) -func GenerateRollupConfig(prod bool, wasmModuleRoot common.Hash, rollupOwner common.Address, chainConfig *params.ChainConfig, serializedChainConfig []byte, loserStakeEscrow common.Address) rollupgen.Config { +func DefaultBufferConfig() rollupgen.BufferConfig { + return rollupgen.BufferConfig{ + Threshold: 600, // 1 hour of blocks + Max: 14400, // 2 days of blocks + ReplenishRateInBasis: 500, // 5% + } +} + +func GenerateRollupConfig(prod bool, wasmModuleRoot common.Hash, rollupOwner common.Address, chainConfig *params.ChainConfig, serializedChainConfig []byte, loserStakeEscrow common.Address, bufferConfig rollupgen.BufferConfig) rollupgen.Config { var confirmPeriod uint64 if prod { confirmPeriod = 45818 @@ -77,6 +85,7 @@ func GenerateRollupConfig(prod bool, wasmModuleRoot common.Hash, rollupOwner com DelaySeconds: big.NewInt(60 * 60 * 24), FutureSeconds: big.NewInt(60 * 60), }, + BufferConfig: bufferConfig, } } diff --git a/cmd/deploy/deploy.go b/cmd/deploy/deploy.go index c70ceb1d94..6060c55586 100644 --- a/cmd/deploy/deploy.go +++ b/cmd/deploy/deploy.go @@ -17,6 +17,7 @@ import ( "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/validator/server_common" @@ -61,6 +62,7 @@ func main() { authorizevalidators := flag.Uint64("authorizevalidators", 0, "Number of validators to preemptively authorize") txTimeout := flag.Duration("txtimeout", 10*time.Minute, "Timeout when waiting for a transaction to be included in a block") prod := flag.Bool("prod", false, "Whether to configure the rollup for production or testing") + isDelayBufferable := flag.Bool("delayBufferable", false, "Whether the sequencer-inbox delay buffer is enabled") flag.Parse() l1ChainId := new(big.Int).SetUint64(*l1ChainIdUint) maxDataSize := new(big.Int).SetUint64(*maxDataSizeUint) @@ -170,6 +172,11 @@ func main() { panic(fmt.Errorf("failed to deserialize chain config: %w", err)) } + var bufferConfig rollupgen.BufferConfig + if *isDelayBufferable { + bufferConfig = arbnode.DefaultBufferConfig() + } + arbSys, _ := precompilesgen.NewArbSys(types.ArbSysAddress, l1client) l1Reader, err := headerreader.New(ctx, l1client, func() *headerreader.Config { return &headerReaderConfig }, arbSys) if err != nil { @@ -186,7 +193,7 @@ func main() { batchPosters, batchPosterManagerAddress, *authorizevalidators, - arbnode.GenerateRollupConfig(*prod, moduleRoot, ownerAddress, &chainConfig, chainConfigJson, loserEscrowAddress), + arbnode.GenerateRollupConfig(*prod, moduleRoot, ownerAddress, &chainConfig, chainConfigJson, loserEscrowAddress, bufferConfig), nativeToken, maxDataSize, true, diff --git a/deploy/deploy.go b/deploy/deploy.go index bb4b2e6594..858d06db89 100644 --- a/deploy/deploy.go +++ b/deploy/deploy.go @@ -49,16 +49,27 @@ func deployBridgeCreator(ctx context.Context, parentChainReader *headerreader.He return common.Address{}, fmt.Errorf("blob basefee reader deploy error: %w", err) } } - seqInboxTemplateEthBased, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, false) + seqInboxTemplateEthBased, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, false, false) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { return common.Address{}, fmt.Errorf("sequencer inbox eth based deploy error: %w", err) } - seqInboxTemplateERC20Based, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, true) + delayBufferableSeqInboxTemplateEthBased, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, false, true) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("delay bufferable sequencer inbox eth based deploy error: %w", err) + } + + seqInboxTemplateERC20Based, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, true, false) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { return common.Address{}, fmt.Errorf("sequencer inbox erc20 based deploy error: %w", err) } + delayBufferableSeqInboxTemplateERC20Based, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, true, true) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("delay bufferable sequencer inbox erc20 based deploy error: %w", err) + } inboxTemplate, tx, _, err := bridgegen.DeployInbox(auth, client, maxDataSize) err = andTxSucceeded(ctx, parentChainReader, tx, err) @@ -78,12 +89,13 @@ func deployBridgeCreator(ctx context.Context, parentChainReader *headerreader.He return common.Address{}, fmt.Errorf("outbox deploy error: %w", err) } - ethBasedTemplates := rollupgen.BridgeCreatorBridgeContracts{ - Bridge: bridgeTemplate, - SequencerInbox: seqInboxTemplateEthBased, - Inbox: inboxTemplate, - RollupEventInbox: rollupEventBridgeTemplate, - Outbox: outboxTemplate, + ethBasedTemplates := rollupgen.BridgeCreatorBridgeTemplates{ + Bridge: bridgeTemplate, + SequencerInbox: seqInboxTemplateEthBased, + DelayBufferableSequencerInbox: delayBufferableSeqInboxTemplateEthBased, + Inbox: inboxTemplate, + RollupEventInbox: rollupEventBridgeTemplate, + Outbox: outboxTemplate, } /// deploy ERC20 based templates @@ -111,12 +123,13 @@ func deployBridgeCreator(ctx context.Context, parentChainReader *headerreader.He return common.Address{}, fmt.Errorf("outbox deploy error: %w", err) } - erc20BasedTemplates := rollupgen.BridgeCreatorBridgeContracts{ - Bridge: erc20BridgeTemplate, - SequencerInbox: seqInboxTemplateERC20Based, - Inbox: erc20InboxTemplate, - RollupEventInbox: erc20RollupEventBridgeTemplate, - Outbox: erc20OutboxTemplate, + erc20BasedTemplates := rollupgen.BridgeCreatorBridgeTemplates{ + Bridge: erc20BridgeTemplate, + SequencerInbox: seqInboxTemplateERC20Based, + DelayBufferableSequencerInbox: delayBufferableSeqInboxTemplateERC20Based, + Inbox: erc20InboxTemplate, + RollupEventInbox: erc20RollupEventBridgeTemplate, + Outbox: erc20OutboxTemplate, } bridgeCreatorAddr, tx, _, err := rollupgen.DeployBridgeCreator(auth, client, ethBasedTemplates, erc20BasedTemplates) @@ -256,7 +269,6 @@ func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.He for i := uint64(1); i <= authorizeValidators; i++ { validatorAddrs = append(validatorAddrs, crypto.CreateAddress(validatorWalletCreator, i)) } - deployParams := rollupgen.RollupCreatorRollupDeploymentParams{ Config: config, Validators: validatorAddrs, @@ -272,6 +284,7 @@ func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.He deployAuth, deployParams, ) + if err != nil { return nil, fmt.Errorf("error submitting create rollup tx: %w", err) } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 027a41d875..f4ea03a105 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -76,6 +76,7 @@ import ( "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" "github.com/offchainlabs/nitro/statetransfer" "github.com/offchainlabs/nitro/util/testhelpers" @@ -252,6 +253,7 @@ type NodeBuilder struct { l3InitMessage *arbostypes.ParsedInitMessage withProdConfirmPeriodBlocks bool wasmCacheTag uint32 + isDelayBufferable bool // Created nodes L1 *TestClient @@ -364,6 +366,11 @@ func (b *NodeBuilder) WithStylusLongTermCache(enabled bool) *NodeBuilder { return b } +func (b *NodeBuilder) WithDelayBuffer(enabled bool) *NodeBuilder { + b.isDelayBufferable = enabled + return b +} + func (b *NodeBuilder) Build(t *testing.T) func() { b.CheckConfig(t) if b.withL1 { @@ -413,6 +420,7 @@ func (b *NodeBuilder) BuildL1(t *testing.T) { locator.LatestWasmModuleRoot(), b.withProdConfirmPeriodBlocks, true, + b.isDelayBufferable, ) b.L1.cleanup = func() { requireClose(t, b.L1.Stack) } } @@ -516,6 +524,7 @@ func (b *NodeBuilder) BuildL3OnL2(t *testing.T) func() { locator.LatestWasmModuleRoot(), b.l3Config.withProdConfirmPeriodBlocks, false, + false, ) b.L3 = buildOnParentChain( @@ -1259,6 +1268,7 @@ func deployOnParentChain( wasmModuleRoot common.Hash, prodConfirmPeriodBlocks bool, chainSupportsBlobs bool, + isDelayBufferable bool, ) (*chaininfo.RollupAddresses, *arbostypes.ParsedInitMessage) { parentChainInfo.GenerateAccount("RollupOwner") parentChainInfo.GenerateAccount("Sequencer") @@ -1281,6 +1291,11 @@ func deployOnParentChain( parentChainReader.Start(ctx) defer parentChainReader.StopAndWait() + var bufferConfig rollupgen.BufferConfig + if isDelayBufferable { + bufferConfig = arbnode.DefaultBufferConfig() + } + nativeToken := common.Address{} maxDataSize := big.NewInt(117964) addresses, err := deploy.DeployOnParentChain( @@ -1290,7 +1305,7 @@ func deployOnParentChain( []common.Address{parentChainInfo.GetAddress("Sequencer")}, parentChainInfo.GetAddress("RollupOwner"), 0, - arbnode.GenerateRollupConfig(prodConfirmPeriodBlocks, wasmModuleRoot, parentChainInfo.GetAddress("RollupOwner"), chainConfig, serializedChainConfig, common.Address{}), + arbnode.GenerateRollupConfig(prodConfirmPeriodBlocks, wasmModuleRoot, parentChainInfo.GetAddress("RollupOwner"), chainConfig, serializedChainConfig, common.Address{}, bufferConfig), nativeToken, maxDataSize, chainSupportsBlobs, diff --git a/system_tests/full_challenge_impl_test.go b/system_tests/full_challenge_impl_test.go index 4d902f87ba..30b7352892 100644 --- a/system_tests/full_challenge_impl_test.go +++ b/system_tests/full_challenge_impl_test.go @@ -215,6 +215,7 @@ func setupSequencerInboxStub(ctx context.Context, t *testing.T, l1Info *Blockcha big.NewInt(117964), reader4844, false, + false, ) Require(t, err) _, err = EnsureTxSucceeded(ctx, l1Client, tx) From 4259e94f10d1d0bd1eb9fbcd841a3ea136fafe3a Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 22 Oct 2024 17:53:46 -0300 Subject: [PATCH 07/25] Fix delay proof Get the delay message accumulator from the previous message. --- arbnode/delay_buffer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go index c0e317e27c..4b79455c64 100644 --- a/arbnode/delay_buffer.go +++ b/arbnode/delay_buffer.go @@ -61,7 +61,7 @@ func GenDelayProof(ctx context.Context, message *arbostypes.MessageWithMetadata, var beforeDelayedAcc common.Hash if seqNum > 0 { var err error - beforeDelayedAcc, err = inbox.GetDelayedAcc(seqNum) + beforeDelayedAcc, err = inbox.GetDelayedAcc(seqNum - 1) if err != nil { return nil, err } From a6c9b2a102a2c1c40896372e35add5d25934bbd9 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Wed, 23 Oct 2024 11:40:18 -0300 Subject: [PATCH 08/25] Fix delay buffer threshold check --- arbnode/batch_poster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 0916aabf00..fc1a789db9 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -1392,7 +1392,7 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) } latestBlock := latestHeader.Number.Uint64() firstDelayedMsgBlock := b.building.firstDelayedMsg.Message.Header.BlockNumber - if latestBlock > firstDelayedMsgBlock+delayBuffer.Threshold { + if latestBlock >= firstDelayedMsgBlock+delayBuffer.Threshold { log.Info("force post batch because of the delay buffer", "firstDelayedMsgBlock", firstDelayedMsgBlock, "threshold", delayBuffer.Threshold, From ba1079d29aad47fcf9cafbba3546a3e7640929fd Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Wed, 23 Oct 2024 11:40:37 -0300 Subject: [PATCH 09/25] Fix off-by-one error in delay proof --- arbnode/delay_buffer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go index 4b79455c64..508fec1b35 100644 --- a/arbnode/delay_buffer.go +++ b/arbnode/delay_buffer.go @@ -57,7 +57,10 @@ func GetDelayBufferConfig(ctx context.Context, sequencerInbox *bridgegen.Sequenc func GenDelayProof(ctx context.Context, message *arbostypes.MessageWithMetadata, inbox *InboxTracker) ( *bridgegen.DelayProof, error) { - seqNum := message.DelayedMessagesRead + if message.DelayedMessagesRead == 0 { + return nil, fmt.Errorf("BUG: trying to generate delay proof without delayed message") + } + seqNum := message.DelayedMessagesRead - 1 var beforeDelayedAcc common.Hash if seqNum > 0 { var err error From 5cc8a44a27d394c983384c4cadbb8ba5c9eec522 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Wed, 23 Oct 2024 16:40:28 -0300 Subject: [PATCH 10/25] Test batch poster with delay buffer enabled --- system_tests/batch_poster_test.go | 51 +++++++++++++++++++++++++++ system_tests/common_test.go | 58 +++++++++++++++---------------- 2 files changed, 80 insertions(+), 29 deletions(-) diff --git a/system_tests/batch_poster_test.go b/system_tests/batch_poster_test.go index 0ec03e84c4..6b602d38a8 100644 --- a/system_tests/batch_poster_test.go +++ b/system_tests/batch_poster_test.go @@ -14,6 +14,7 @@ import ( "github.com/andybalholm/brotli" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" @@ -363,3 +364,53 @@ func TestAllowPostingFirstBatchWhenSequencerMessageCountMismatchEnabled(t *testi func TestAllowPostingFirstBatchWhenSequencerMessageCountMismatchDisabled(t *testing.T) { testAllowPostingFirstBatchWhenSequencerMessageCountMismatch(t, false) } + +func TestBatchPosterDelayBuffer(t *testing.T) { + const messagesPerBatch = 10 + const threshold = 100 + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) + builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer + cleanup := builder.Build(t) + defer cleanup() + builder.L2Info.GenerateAccount("User2") + + testClientB, cleanupB := builder.Build2ndNode(t, &SecondNodeParams{}) + defer cleanupB() + + sequenceInbox, err := bridgegen.NewSequencerInbox(builder.L1Info.GetAddress("SequencerInbox"), builder.L1.Client) + Require(t, err) + getBatchCount := func() uint64 { + batchCount, err := sequenceInbox.BatchCount(&bind.CallOpts{Context: ctx}) + Require(t, err) + return batchCount.Uint64() + } + + t.Run("SendsDelayedMessages", func(t *testing.T) { + previousBatchCount := getBatchCount() + const numBatches = 3 + for batch := uint64(0); batch < numBatches; batch++ { + txs := make(types.Transactions, messagesPerBatch) + for i := range txs { + txs[i] = builder.L2Info.PrepareTx("Owner", "User2", builder.L2Info.TransferGas, common.Big1, nil) + } + SendSignedTxesInBatchViaL1(t, ctx, builder.L1Info, builder.L1.Client, builder.L2.Client, txs) + time.Sleep(time.Second) + if currBatchCount := getBatchCount(); currBatchCount != previousBatchCount+batch { + t.Fatalf("expected batch count %v; got %v", previousBatchCount+batch, currBatchCount) + } + // Advance L1 to force the delay buffer + AdvanceL1(t, ctx, builder.L1.Client, builder.L1Info, threshold) + if currBatchCount := getBatchCount(); currBatchCount != previousBatchCount+batch+1 { + t.Fatalf("expected batch count %v; got %v", previousBatchCount+batch+1, currBatchCount) + } + for _, tx := range txs { + _, err := testClientB.EnsureTxSucceeded(tx) + Require(t, err, "tx not found on second node") + } + } + }) +} diff --git a/system_tests/common_test.go b/system_tests/common_test.go index f4ea03a105..4bbf7c473c 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -76,7 +76,6 @@ import ( "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" - "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" "github.com/offchainlabs/nitro/statetransfer" "github.com/offchainlabs/nitro/util/testhelpers" @@ -253,7 +252,7 @@ type NodeBuilder struct { l3InitMessage *arbostypes.ParsedInitMessage withProdConfirmPeriodBlocks bool wasmCacheTag uint32 - isDelayBufferable bool + delayBufferThreshold uint64 // Created nodes L1 *TestClient @@ -366,8 +365,11 @@ func (b *NodeBuilder) WithStylusLongTermCache(enabled bool) *NodeBuilder { return b } -func (b *NodeBuilder) WithDelayBuffer(enabled bool) *NodeBuilder { - b.isDelayBufferable = enabled +// WithDelayBuffer sets the delay-buffer threshold, which is the number of blocks the batch-poster +// is allowed to delay a batch with a delayed message. +// Setting the threshold to zero disabled the delay buffer (default behaviour). +func (b *NodeBuilder) WithDelayBuffer(threshold uint64) *NodeBuilder { + b.delayBufferThreshold = threshold return b } @@ -420,7 +422,7 @@ func (b *NodeBuilder) BuildL1(t *testing.T) { locator.LatestWasmModuleRoot(), b.withProdConfirmPeriodBlocks, true, - b.isDelayBufferable, + b.delayBufferThreshold, ) b.L1.cleanup = func() { requireClose(t, b.L1.Stack) } } @@ -524,7 +526,7 @@ func (b *NodeBuilder) BuildL3OnL2(t *testing.T) func() { locator.LatestWasmModuleRoot(), b.l3Config.withProdConfirmPeriodBlocks, false, - false, + 0, ) b.L3 = buildOnParentChain( @@ -882,6 +884,21 @@ func BridgeBalance( return tx, res } +// AdvanceL1 sends dummy transactions to L1 to create blocks. +func AdvanceL1( + t *testing.T, + ctx context.Context, + l1client *ethclient.Client, + l1info *BlockchainTestInfo, + numBlocks int, +) { + for i := 0; i < numBlocks; i++ { + SendWaitTestTransactions(t, ctx, l1client, []*types.Transaction{ + l1info.PrepareTx("Faucet", "Faucet", 30000, big.NewInt(1e12), nil), + }) + } +} + func SendSignedTxesInBatchViaL1( t *testing.T, ctx context.Context, @@ -901,12 +918,7 @@ func SendSignedTxesInBatchViaL1( _, err = EnsureTxSucceeded(ctx, l1client, l1tx) Require(t, err) - // sending l1 messages creates l1 blocks.. make enough to get that delayed inbox message in - for i := 0; i < 30; i++ { - SendWaitTestTransactions(t, ctx, l1client, []*types.Transaction{ - l1info.PrepareTx("Faucet", "Faucet", 30000, big.NewInt(1e12), nil), - }) - } + AdvanceL1(t, ctx, l1client, l1info, 30) var receipts types.Receipts for _, tx := range delayedTxes { receipt, err := EnsureTxSucceeded(ctx, l2client, tx) @@ -953,12 +965,7 @@ func SendSignedTxViaL1( _, err = EnsureTxSucceeded(ctx, l1client, l1tx) Require(t, err) - // sending l1 messages creates l1 blocks.. make enough to get that delayed inbox message in - for i := 0; i < 30; i++ { - SendWaitTestTransactions(t, ctx, l1client, []*types.Transaction{ - l1info.PrepareTx("Faucet", "Faucet", 30000, big.NewInt(1e12), nil), - }) - } + AdvanceL1(t, ctx, l1client, l1info, 30) receipt, err := EnsureTxSucceeded(ctx, l2client, delayedTx) Require(t, err) return receipt @@ -1004,12 +1011,7 @@ func SendUnsignedTxViaL1( _, err = EnsureTxSucceeded(ctx, l1client, l1tx) Require(t, err) - // sending l1 messages creates l1 blocks.. make enough to get that delayed inbox message in - for i := 0; i < 30; i++ { - SendWaitTestTransactions(t, ctx, l1client, []*types.Transaction{ - l1info.PrepareTx("Faucet", "Faucet", 30000, big.NewInt(1e12), nil), - }) - } + AdvanceL1(t, ctx, l1client, l1info, 30) receipt, err := EnsureTxSucceeded(ctx, l2client, unsignedTx) Require(t, err) return receipt @@ -1268,7 +1270,7 @@ func deployOnParentChain( wasmModuleRoot common.Hash, prodConfirmPeriodBlocks bool, chainSupportsBlobs bool, - isDelayBufferable bool, + delayBufferThreshold uint64, ) (*chaininfo.RollupAddresses, *arbostypes.ParsedInitMessage) { parentChainInfo.GenerateAccount("RollupOwner") parentChainInfo.GenerateAccount("Sequencer") @@ -1291,10 +1293,8 @@ func deployOnParentChain( parentChainReader.Start(ctx) defer parentChainReader.StopAndWait() - var bufferConfig rollupgen.BufferConfig - if isDelayBufferable { - bufferConfig = arbnode.DefaultBufferConfig() - } + bufferConfig := arbnode.DefaultBufferConfig() + bufferConfig.Threshold = delayBufferThreshold nativeToken := common.Address{} maxDataSize := big.NewInt(117964) From 410a65df41a0ff9223cff118a50073c5227127c9 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Thu, 24 Oct 2024 15:54:05 -0300 Subject: [PATCH 11/25] Add two more delay-buffer tests * Test batch poster without delay buffer works * Test delay buffer don't force batch without delayed messages --- system_tests/batch_poster_test.go | 129 ++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 34 deletions(-) diff --git a/system_tests/batch_poster_test.go b/system_tests/batch_poster_test.go index 6b602d38a8..2ba3da328e 100644 --- a/system_tests/batch_poster_test.go +++ b/system_tests/batch_poster_test.go @@ -6,6 +6,7 @@ package arbtest import ( "context" "crypto/rand" + "errors" "fmt" "math/big" "strings" @@ -365,52 +366,112 @@ func TestAllowPostingFirstBatchWhenSequencerMessageCountMismatchDisabled(t *test testAllowPostingFirstBatchWhenSequencerMessageCountMismatch(t, false) } -func TestBatchPosterDelayBuffer(t *testing.T) { - const messagesPerBatch = 10 - const threshold = 100 +func GetBatchCount(t *testing.T, builder *NodeBuilder) uint64 { + t.Helper() + sequenceInbox, err := bridgegen.NewSequencerInbox(builder.L1Info.GetAddress("SequencerInbox"), builder.L1.Client) + Require(t, err) + batchCount, err := sequenceInbox.BatchCount(&bind.CallOpts{Context: builder.ctx}) + Require(t, err) + return batchCount.Uint64() +} + +func CheckBatchCount(t *testing.T, builder *NodeBuilder, want uint64) { + if got := GetBatchCount(t, builder); got != want { + t.Fatalf("invalid batch count, want %v, got %v", want, got) + } +} + +func testBatchPosterDelayBuffer(t *testing.T, delayBufferEnabled bool) { + const messagesPerBatch = 3 + const numBatches = 3 + var threshold uint64 + if delayBufferEnabled { + threshold = 100 + } ctx, cancel := context.WithCancel(context.Background()) defer cancel() builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) + builder.L2Info.GenerateAccount("User2") builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer cleanup := builder.Build(t) defer cleanup() - builder.L2Info.GenerateAccount("User2") + testClientB, cleanupB := builder.Build2ndNode(t, &SecondNodeParams{}) + defer cleanupB() + + initialBatchCount := GetBatchCount(t, builder) + for batch := uint64(0); batch < numBatches; batch++ { + txs := make(types.Transactions, messagesPerBatch) + for i := range txs { + txs[i] = builder.L2Info.PrepareTx("Owner", "User2", builder.L2Info.TransferGas, common.Big1, nil) + } + SendSignedTxesInBatchViaL1(t, ctx, builder.L1Info, builder.L1.Client, builder.L2.Client, txs) + + // Check batch wasn't sent + _, err := WaitForTx(ctx, testClientB.Client, txs[0].Hash(), 100*time.Millisecond) + if err == nil || !errors.Is(err, context.DeadlineExceeded) { + Fatal(t, "expected context-deadline exceeded error, but got:", err) + } + CheckBatchCount(t, builder, initialBatchCount+batch) + + // Advance L1 to force a batch given the delay buffer threshold + AdvanceL1(t, ctx, builder.L1.Client, builder.L1Info, int(threshold)) // #nosec G115 + if !delayBufferEnabled { + // If the delay buffer is disabled, set max delay to zero to force it + CheckBatchCount(t, builder, initialBatchCount+batch) + builder.nodeConfig.BatchPoster.MaxDelay = 0 + } + for _, tx := range txs { + _, err := testClientB.EnsureTxSucceeded(tx) + Require(t, err, "tx not found on second node") + } + CheckBatchCount(t, builder, initialBatchCount+batch+1) + if !delayBufferEnabled { + builder.nodeConfig.BatchPoster.MaxDelay = time.Hour + } + } +} +func TestBatchPosterDelayBufferEnabled(t *testing.T) { + testBatchPosterDelayBuffer(t, true) +} + +func TestBatchPosterDelayBufferDisabled(t *testing.T) { + testBatchPosterDelayBuffer(t, false) +} + +func TestBatchPosterDelayBufferDontForceNonDelayedMessages(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + const threshold = 100 + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) + builder.L2Info.GenerateAccount("User2") + builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer + cleanup := builder.Build(t) + defer cleanup() testClientB, cleanupB := builder.Build2ndNode(t, &SecondNodeParams{}) defer cleanupB() - sequenceInbox, err := bridgegen.NewSequencerInbox(builder.L1Info.GetAddress("SequencerInbox"), builder.L1.Client) - Require(t, err) - getBatchCount := func() uint64 { - batchCount, err := sequenceInbox.BatchCount(&bind.CallOpts{Context: ctx}) - Require(t, err) - return batchCount.Uint64() + // Send non-delayed message and advance L1 + initialBatchCount := GetBatchCount(t, builder) + const numTxs = 3 + txs := make(types.Transactions, numTxs) + for i := range txs { + txs[i] = builder.L2Info.PrepareTx("Owner", "User2", builder.L2Info.TransferGas, common.Big1, nil) } + builder.L2.SendWaitTestTransactions(t, txs) + AdvanceL1(t, ctx, builder.L1.Client, builder.L1Info, threshold) - t.Run("SendsDelayedMessages", func(t *testing.T) { - previousBatchCount := getBatchCount() - const numBatches = 3 - for batch := uint64(0); batch < numBatches; batch++ { - txs := make(types.Transactions, messagesPerBatch) - for i := range txs { - txs[i] = builder.L2Info.PrepareTx("Owner", "User2", builder.L2Info.TransferGas, common.Big1, nil) - } - SendSignedTxesInBatchViaL1(t, ctx, builder.L1Info, builder.L1.Client, builder.L2.Client, txs) - time.Sleep(time.Second) - if currBatchCount := getBatchCount(); currBatchCount != previousBatchCount+batch { - t.Fatalf("expected batch count %v; got %v", previousBatchCount+batch, currBatchCount) - } - // Advance L1 to force the delay buffer - AdvanceL1(t, ctx, builder.L1.Client, builder.L1Info, threshold) - if currBatchCount := getBatchCount(); currBatchCount != previousBatchCount+batch+1 { - t.Fatalf("expected batch count %v; got %v", previousBatchCount+batch+1, currBatchCount) - } - for _, tx := range txs { - _, err := testClientB.EnsureTxSucceeded(tx) - Require(t, err, "tx not found on second node") - } - } - }) + // Even advancing the L1, the batch won't be posted because it doesn't contain a delayed message + CheckBatchCount(t, builder, initialBatchCount) + + // Set delay to zero to force non-delayed messages + builder.nodeConfig.BatchPoster.MaxDelay = 0 + for _, tx := range txs { + _, err := testClientB.EnsureTxSucceeded(tx) + Require(t, err, "tx not found on second node") + } + CheckBatchCount(t, builder, initialBatchCount+1) } From fb86fad785bdbb0be40d72003a74661093b3ab31 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 28 Oct 2024 15:27:23 -0300 Subject: [PATCH 12/25] Fix gofmt --- staker/multi_protocol/multi_protocol_staker.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/staker/multi_protocol/multi_protocol_staker.go b/staker/multi_protocol/multi_protocol_staker.go index d4d4e1b54f..5f36b8df99 100644 --- a/staker/multi_protocol/multi_protocol_staker.go +++ b/staker/multi_protocol/multi_protocol_staker.go @@ -2,15 +2,16 @@ package multiprotocolstaker import ( "context" - "github.com/offchainlabs/nitro/staker" "time" - "github.com/offchainlabs/bold/solgen/go/bridgegen" - boldrollup "github.com/offchainlabs/bold/solgen/go/rollupgen" + "github.com/offchainlabs/nitro/staker" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" + "github.com/offchainlabs/bold/solgen/go/bridgegen" + boldrollup "github.com/offchainlabs/bold/solgen/go/rollupgen" boldstaker "github.com/offchainlabs/nitro/staker/bold" legacystaker "github.com/offchainlabs/nitro/staker/legacy" From b0d586cb4dcc13d414de86eb35958f5bb04be54a Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Mon, 28 Oct 2024 17:31:15 -0300 Subject: [PATCH 13/25] Use BoLD contracts to test delay buffer Rebase the delay buffer PR on top of BoLD's little merge. Then, use the BoLD version of the contracts when appropriate instead of using the delay-buffer development branch. --- arbnode/batch_poster.go | 3 +- arbnode/delay_buffer.go | 2 +- arbnode/node.go | 37 --- cmd/deploy/deploy.go | 12 +- deploy/deploy.go | 117 +++++++-- deploy/legacy.go | 321 +++++++++++++++++++++++ system_tests/batch_poster_test.go | 10 +- system_tests/common_test.go | 103 ++++++-- system_tests/full_challenge_impl_test.go | 1 - 9 files changed, 509 insertions(+), 97 deletions(-) create mode 100644 deploy/legacy.go diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index fc1a789db9..eb0a98240c 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "github.com/offchainlabs/bold/solgen/go/bridgegen" "github.com/offchainlabs/nitro/arbnode/dataposter" "github.com/offchainlabs/nitro/arbnode/dataposter/storage" "github.com/offchainlabs/nitro/arbnode/redislock" @@ -44,7 +45,6 @@ import ( "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/execution" - "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/blobs" @@ -317,7 +317,6 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e if err = opts.Config().Validate(); err != nil { return nil, err } - // TODO(delaybuffer) use new bridgegen seqInboxABI, err := bridgegen.SequencerInboxMetaData.GetAbi() if err != nil { return nil, err diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go index 508fec1b35..ffef7ee828 100644 --- a/arbnode/delay_buffer.go +++ b/arbnode/delay_buffer.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/offchainlabs/bold/solgen/go/bridgegen" "github.com/offchainlabs/nitro/arbos/arbostypes" - "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util/headerreader" ) diff --git a/arbnode/node.go b/arbnode/node.go index d7d9465205..7445999fcd 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -39,7 +39,6 @@ import ( "github.com/offchainlabs/nitro/execution/gethexec" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" - "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker" boldstaker "github.com/offchainlabs/nitro/staker/bold" legacystaker "github.com/offchainlabs/nitro/staker/legacy" @@ -53,42 +52,6 @@ import ( "github.com/offchainlabs/nitro/wsbroadcastserver" ) -func DefaultBufferConfig() rollupgen.BufferConfig { - return rollupgen.BufferConfig{ - Threshold: 600, // 1 hour of blocks - Max: 14400, // 2 days of blocks - ReplenishRateInBasis: 500, // 5% - } -} - -func GenerateRollupConfig(prod bool, wasmModuleRoot common.Hash, rollupOwner common.Address, chainConfig *params.ChainConfig, serializedChainConfig []byte, loserStakeEscrow common.Address, bufferConfig rollupgen.BufferConfig) rollupgen.Config { - var confirmPeriod uint64 - if prod { - confirmPeriod = 45818 - } else { - confirmPeriod = 20 - } - return rollupgen.Config{ - ConfirmPeriodBlocks: confirmPeriod, - ExtraChallengeTimeBlocks: 200, - StakeToken: common.Address{}, - BaseStake: big.NewInt(params.Ether), - WasmModuleRoot: wasmModuleRoot, - Owner: rollupOwner, - LoserStakeEscrow: loserStakeEscrow, - ChainId: chainConfig.ChainID, - // TODO could the ChainConfig be just []byte? - ChainConfig: string(serializedChainConfig), - SequencerInboxMaxTimeVariation: rollupgen.ISequencerInboxMaxTimeVariation{ - DelayBlocks: big.NewInt(60 * 60 * 24 / 15), - FutureBlocks: big.NewInt(12), - DelaySeconds: big.NewInt(60 * 60 * 24), - FutureSeconds: big.NewInt(60 * 60), - }, - BufferConfig: bufferConfig, - } -} - type Config struct { Sequencer bool `koanf:"sequencer"` ParentChainReader headerreader.Config `koanf:"parent-chain-reader" reload:"hot"` diff --git a/cmd/deploy/deploy.go b/cmd/deploy/deploy.go index 6060c55586..603539196f 100644 --- a/cmd/deploy/deploy.go +++ b/cmd/deploy/deploy.go @@ -17,7 +17,6 @@ import ( "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" - "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/validator/server_common" @@ -26,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "github.com/offchainlabs/nitro/arbnode" "github.com/offchainlabs/nitro/cmd/util" deploycode "github.com/offchainlabs/nitro/deploy" ) @@ -62,7 +60,6 @@ func main() { authorizevalidators := flag.Uint64("authorizevalidators", 0, "Number of validators to preemptively authorize") txTimeout := flag.Duration("txtimeout", 10*time.Minute, "Timeout when waiting for a transaction to be included in a block") prod := flag.Bool("prod", false, "Whether to configure the rollup for production or testing") - isDelayBufferable := flag.Bool("delayBufferable", false, "Whether the sequencer-inbox delay buffer is enabled") flag.Parse() l1ChainId := new(big.Int).SetUint64(*l1ChainIdUint) maxDataSize := new(big.Int).SetUint64(*maxDataSizeUint) @@ -172,11 +169,6 @@ func main() { panic(fmt.Errorf("failed to deserialize chain config: %w", err)) } - var bufferConfig rollupgen.BufferConfig - if *isDelayBufferable { - bufferConfig = arbnode.DefaultBufferConfig() - } - arbSys, _ := precompilesgen.NewArbSys(types.ArbSysAddress, l1client) l1Reader, err := headerreader.New(ctx, l1client, func() *headerreader.Config { return &headerReaderConfig }, arbSys) if err != nil { @@ -186,14 +178,14 @@ func main() { defer l1Reader.StopAndWait() nativeToken := common.HexToAddress(*nativeTokenAddressString) - deployedAddresses, err := deploycode.DeployOnParentChain( + deployedAddresses, err := deploycode.DeployLegacyOnParentChain( ctx, l1Reader, l1TransactionOpts, batchPosters, batchPosterManagerAddress, *authorizevalidators, - arbnode.GenerateRollupConfig(*prod, moduleRoot, ownerAddress, &chainConfig, chainConfigJson, loserEscrowAddress, bufferConfig), + deploycode.GenerateLegacyRollupConfig(*prod, moduleRoot, ownerAddress, &chainConfig, chainConfigJson, loserEscrowAddress), nativeToken, maxDataSize, true, diff --git a/deploy/deploy.go b/deploy/deploy.go index 858d06db89..6a71dd9673 100644 --- a/deploy/deploy.go +++ b/deploy/deploy.go @@ -10,16 +10,89 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + "github.com/offchainlabs/bold/solgen/go/bridgegen" + "github.com/offchainlabs/bold/solgen/go/challengeV2gen" + "github.com/offchainlabs/bold/solgen/go/ospgen" + "github.com/offchainlabs/bold/solgen/go/rollupgen" + "github.com/offchainlabs/bold/solgen/go/yulgen" "github.com/offchainlabs/nitro/cmd/chaininfo" - "github.com/offchainlabs/nitro/solgen/go/bridgegen" - "github.com/offchainlabs/nitro/solgen/go/challengegen" - "github.com/offchainlabs/nitro/solgen/go/ospgen" - "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" - "github.com/offchainlabs/nitro/solgen/go/yulgen" "github.com/offchainlabs/nitro/util/headerreader" ) +// lint:require-exhaustive-initialization +type RollupConfigOpts struct { + Prod bool + WasmModuleRoot common.Hash + RollupOwner common.Address + ChainConfig *params.ChainConfig + SerializedChainConfig []byte + LoserStakeEscrow common.Address + MiniStakeValues []*big.Int + StakeToken common.Address + GenesisExecutionState rollupgen.AssertionState + GenesisInboxCount *big.Int + AnyTrustFastConfirmer common.Address + LayerZeroBlockEdgeHeight uint64 + LayerZeroBigStepEdgeHeight uint64 + LayerZeroSmallStepEdgeHeight uint64 + NumBigStepLevel uint8 + BufferConfig rollupgen.BufferConfig +} + +func DefaultBufferConfig() rollupgen.BufferConfig { + return rollupgen.BufferConfig{ + Threshold: 600, // 1 hour of blocks + Max: 14400, // 2 days of blocks + ReplenishRateInBasis: 500, // 5% + } +} + +func GenerateRollupConfig(opts *RollupConfigOpts) rollupgen.Config { + var confirmPeriod uint64 + if opts.Prod { + confirmPeriod = 45818 + } else { + confirmPeriod = 25 + } + + var gracePeriod uint64 + if opts.Prod { + gracePeriod = 14400 + } else { + gracePeriod = 3 + } + + cfg := rollupgen.Config{ + ConfirmPeriodBlocks: confirmPeriod, + StakeToken: opts.StakeToken, + BaseStake: big.NewInt(1), + WasmModuleRoot: opts.WasmModuleRoot, + Owner: opts.RollupOwner, + LoserStakeEscrow: opts.LoserStakeEscrow, + ChainId: opts.ChainConfig.ChainID, + ChainConfig: string(opts.SerializedChainConfig), + MiniStakeValues: opts.MiniStakeValues, + SequencerInboxMaxTimeVariation: rollupgen.ISequencerInboxMaxTimeVariation{ + DelayBlocks: big.NewInt(60 * 60 * 24 / 15), + FutureBlocks: big.NewInt(12), + DelaySeconds: big.NewInt(60 * 60 * 24), + FutureSeconds: big.NewInt(60 * 60), + }, + LayerZeroBlockEdgeHeight: new(big.Int).SetUint64(opts.LayerZeroBlockEdgeHeight), + LayerZeroBigStepEdgeHeight: new(big.Int).SetUint64(opts.LayerZeroBigStepEdgeHeight), + LayerZeroSmallStepEdgeHeight: new(big.Int).SetUint64(opts.LayerZeroSmallStepEdgeHeight), + GenesisAssertionState: opts.GenesisExecutionState, + GenesisInboxCount: opts.GenesisInboxCount, + AnyTrustFastConfirmer: opts.AnyTrustFastConfirmer, + NumBigStepLevel: opts.NumBigStepLevel, + ChallengeGracePeriodBlocks: gracePeriod, + BufferConfig: opts.BufferConfig, + } + return cfg +} + func andTxSucceeded(ctx context.Context, parentChainReader *headerreader.HeaderReader, tx *types.Transaction, err error) error { if err != nil { return fmt.Errorf("error submitting tx: %w", err) @@ -167,7 +240,7 @@ func deployChallengeFactory(ctx context.Context, parentChainReader *headerreader return common.Address{}, common.Address{}, fmt.Errorf("ospHostIo deploy error: %w", err) } - challengeManagerAddr, tx, _, err := challengegen.DeployChallengeManager(auth, client) + challengeManagerAddr, tx, _, err := challengeV2gen.DeployEdgeChallengeManager(auth, client) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { return common.Address{}, common.Address{}, fmt.Errorf("challenge manager deploy error: %w", err) @@ -182,57 +255,51 @@ func deployChallengeFactory(ctx context.Context, parentChainReader *headerreader return ospEntryAddr, challengeManagerAddr, nil } -func deployRollupCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (*rollupgen.RollupCreator, common.Address, common.Address, common.Address, error) { +func deployRollupCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (*rollupgen.RollupCreator, common.Address, common.Address, error) { bridgeCreator, err := deployBridgeCreator(ctx, parentChainReader, auth, maxDataSize, chainSupportsBlobs) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) } ospEntryAddr, challengeManagerAddr, err := deployChallengeFactory(ctx, parentChainReader, auth) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, err + return nil, common.Address{}, common.Address{}, err } rollupAdminLogic, tx, _, err := rollupgen.DeployRollupAdminLogic(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup admin logic deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup admin logic deploy error: %w", err) } rollupUserLogic, tx, _, err := rollupgen.DeployRollupUserLogic(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup user logic deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup user logic deploy error: %w", err) } rollupCreatorAddress, tx, rollupCreator, err := rollupgen.DeployRollupCreator(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup creator deploy error: %w", err) } upgradeExecutor, tx, _, err := upgrade_executorgen.DeployUpgradeExecutor(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("upgrade executor deploy error: %w", err) - } - - validatorUtils, tx, _, err := rollupgen.DeployValidatorUtils(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator utils deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("upgrade executor deploy error: %w", err) } validatorWalletCreator, tx, _, err := rollupgen.DeployValidatorWalletCreator(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator wallet creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("validator wallet creator deploy error: %w", err) } l2FactoriesDeployHelper, tx, _, err := rollupgen.DeployDeployHelper(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("deploy helper creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("deploy helper creator deploy error: %w", err) } tx, err = rollupCreator.SetTemplates( @@ -243,16 +310,15 @@ func deployRollupCreator(ctx context.Context, parentChainReader *headerreader.He rollupAdminLogic, rollupUserLogic, upgradeExecutor, - validatorUtils, validatorWalletCreator, l2FactoriesDeployHelper, ) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup set template error: %w", err) + return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup set template error: %w", err) } - return rollupCreator, rollupCreatorAddress, validatorUtils, validatorWalletCreator, nil + return rollupCreator, rollupCreatorAddress, validatorWalletCreator, nil } func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.HeaderReader, deployAuth *bind.TransactOpts, batchPosters []common.Address, batchPosterManager common.Address, authorizeValidators uint64, config rollupgen.Config, nativeToken common.Address, maxDataSize *big.Int, chainSupportsBlobs bool) (*chaininfo.RollupAddresses, error) { @@ -260,7 +326,7 @@ func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.He return nil, errors.New("no machine specified") } - rollupCreator, _, validatorUtils, validatorWalletCreator, err := deployRollupCreator(ctx, parentChainReader, deployAuth, maxDataSize, chainSupportsBlobs) + rollupCreator, _, validatorWalletCreator, err := deployRollupCreator(ctx, parentChainReader, deployAuth, maxDataSize, chainSupportsBlobs) if err != nil { return nil, fmt.Errorf("error deploying rollup creator: %w", err) } @@ -305,7 +371,6 @@ func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.He Rollup: info.RollupAddress, NativeToken: nativeToken, UpgradeExecutor: info.UpgradeExecutor, - ValidatorUtils: validatorUtils, ValidatorWalletCreator: validatorWalletCreator, }, nil } diff --git a/deploy/legacy.go b/deploy/legacy.go new file mode 100644 index 0000000000..908052ae08 --- /dev/null +++ b/deploy/legacy.go @@ -0,0 +1,321 @@ +package deploy + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + "github.com/offchainlabs/nitro/cmd/chaininfo" + "github.com/offchainlabs/nitro/solgen/go/bridgegen" + "github.com/offchainlabs/nitro/solgen/go/challengegen" + "github.com/offchainlabs/nitro/solgen/go/ospgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" + "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" + "github.com/offchainlabs/nitro/solgen/go/yulgen" + "github.com/offchainlabs/nitro/util/headerreader" +) + +func GenerateLegacyRollupConfig( + prod bool, + wasmModuleRoot common.Hash, + rollupOwner common.Address, + chainConfig *params.ChainConfig, + serializedChainConfig []byte, + loserStakeEscrow common.Address, +) rollupgen.Config { + var confirmPeriod uint64 + if prod { + confirmPeriod = 45818 + } else { + confirmPeriod = 20 + } + return rollupgen.Config{ + ConfirmPeriodBlocks: confirmPeriod, + ExtraChallengeTimeBlocks: 200, + StakeToken: common.Address{}, + BaseStake: big.NewInt(params.Ether), + WasmModuleRoot: wasmModuleRoot, + Owner: rollupOwner, + LoserStakeEscrow: loserStakeEscrow, + ChainId: chainConfig.ChainID, + // TODO could the ChainConfig be just []byte? + ChainConfig: string(serializedChainConfig), + SequencerInboxMaxTimeVariation: rollupgen.ISequencerInboxMaxTimeVariation{ + DelayBlocks: big.NewInt(60 * 60 * 24 / 15), + FutureBlocks: big.NewInt(12), + DelaySeconds: big.NewInt(60 * 60 * 24), + FutureSeconds: big.NewInt(60 * 60), + }, + } +} + +func deployLegacyBridgeCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (common.Address, error) { + client := parentChainReader.Client() + + /// deploy eth based templates + bridgeTemplate, tx, _, err := bridgegen.DeployBridge(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("bridge deploy error: %w", err) + } + + var reader4844 common.Address + if chainSupportsBlobs { + reader4844, tx, _, err = yulgen.DeployReader4844(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("blob basefee reader deploy error: %w", err) + } + } + seqInboxTemplateEthBased, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, false) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("sequencer inbox eth based deploy error: %w", err) + } + seqInboxTemplateERC20Based, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, true) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("sequencer inbox erc20 based deploy error: %w", err) + } + + inboxTemplate, tx, _, err := bridgegen.DeployInbox(auth, client, maxDataSize) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("inbox deploy error: %w", err) + } + + rollupEventBridgeTemplate, tx, _, err := rollupgen.DeployRollupEventInbox(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("rollup event bridge deploy error: %w", err) + } + + outboxTemplate, tx, _, err := bridgegen.DeployOutbox(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("outbox deploy error: %w", err) + } + + ethBasedTemplates := rollupgen.BridgeCreatorBridgeContracts{ + Bridge: bridgeTemplate, + SequencerInbox: seqInboxTemplateEthBased, + Inbox: inboxTemplate, + RollupEventInbox: rollupEventBridgeTemplate, + Outbox: outboxTemplate, + } + + /// deploy ERC20 based templates + erc20BridgeTemplate, tx, _, err := bridgegen.DeployERC20Bridge(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("bridge deploy error: %w", err) + } + + erc20InboxTemplate, tx, _, err := bridgegen.DeployERC20Inbox(auth, client, maxDataSize) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("inbox deploy error: %w", err) + } + + erc20RollupEventBridgeTemplate, tx, _, err := rollupgen.DeployERC20RollupEventInbox(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("rollup event bridge deploy error: %w", err) + } + + erc20OutboxTemplate, tx, _, err := bridgegen.DeployERC20Outbox(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("outbox deploy error: %w", err) + } + + erc20BasedTemplates := rollupgen.BridgeCreatorBridgeContracts{ + Bridge: erc20BridgeTemplate, + SequencerInbox: seqInboxTemplateERC20Based, + Inbox: erc20InboxTemplate, + RollupEventInbox: erc20RollupEventBridgeTemplate, + Outbox: erc20OutboxTemplate, + } + + bridgeCreatorAddr, tx, _, err := rollupgen.DeployBridgeCreator(auth, client, ethBasedTemplates, erc20BasedTemplates) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) + } + + return bridgeCreatorAddr, nil +} + +func deployLegacyChallengeFactory(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts) (common.Address, common.Address, error) { + client := parentChainReader.Client() + osp0, tx, _, err := ospgen.DeployOneStepProver0(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, common.Address{}, fmt.Errorf("osp0 deploy error: %w", err) + } + + ospMem, tx, _, err := ospgen.DeployOneStepProverMemory(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, common.Address{}, fmt.Errorf("ospMemory deploy error: %w", err) + } + + ospMath, tx, _, err := ospgen.DeployOneStepProverMath(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, common.Address{}, fmt.Errorf("ospMath deploy error: %w", err) + } + + ospHostIo, tx, _, err := ospgen.DeployOneStepProverHostIo(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, common.Address{}, fmt.Errorf("ospHostIo deploy error: %w", err) + } + + challengeManagerAddr, tx, _, err := challengegen.DeployChallengeManager(auth, client) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, common.Address{}, fmt.Errorf("challenge manager deploy error: %w", err) + } + + ospEntryAddr, tx, _, err := ospgen.DeployOneStepProofEntry(auth, client, osp0, ospMem, ospMath, ospHostIo) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return common.Address{}, common.Address{}, fmt.Errorf("ospEntry deploy error: %w", err) + } + + return ospEntryAddr, challengeManagerAddr, nil +} + +func deployLegacyRollupCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (*rollupgen.RollupCreator, common.Address, common.Address, common.Address, error) { + bridgeCreator, err := deployLegacyBridgeCreator(ctx, parentChainReader, auth, maxDataSize, chainSupportsBlobs) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) + } + + ospEntryAddr, challengeManagerAddr, err := deployLegacyChallengeFactory(ctx, parentChainReader, auth) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, err + } + + rollupAdminLogic, tx, _, err := rollupgen.DeployRollupAdminLogic(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup admin logic deploy error: %w", err) + } + + rollupUserLogic, tx, _, err := rollupgen.DeployRollupUserLogic(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup user logic deploy error: %w", err) + } + + rollupCreatorAddress, tx, rollupCreator, err := rollupgen.DeployRollupCreator(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup creator deploy error: %w", err) + } + + upgradeExecutor, tx, _, err := upgrade_executorgen.DeployUpgradeExecutor(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("upgrade executor deploy error: %w", err) + } + + validatorUtils, tx, _, err := rollupgen.DeployValidatorUtils(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator utils deploy error: %w", err) + } + + validatorWalletCreator, tx, _, err := rollupgen.DeployValidatorWalletCreator(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator wallet creator deploy error: %w", err) + } + + l2FactoriesDeployHelper, tx, _, err := rollupgen.DeployDeployHelper(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("deploy helper creator deploy error: %w", err) + } + + tx, err = rollupCreator.SetTemplates( + auth, + bridgeCreator, + ospEntryAddr, + challengeManagerAddr, + rollupAdminLogic, + rollupUserLogic, + upgradeExecutor, + validatorUtils, + validatorWalletCreator, + l2FactoriesDeployHelper, + ) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup set template error: %w", err) + } + + return rollupCreator, rollupCreatorAddress, validatorUtils, validatorWalletCreator, nil +} + +func DeployLegacyOnParentChain(ctx context.Context, parentChainReader *headerreader.HeaderReader, deployAuth *bind.TransactOpts, batchPosters []common.Address, batchPosterManager common.Address, authorizeValidators uint64, config rollupgen.Config, nativeToken common.Address, maxDataSize *big.Int, chainSupportsBlobs bool) (*chaininfo.RollupAddresses, error) { + if config.WasmModuleRoot == (common.Hash{}) { + return nil, errors.New("no machine specified") + } + + rollupCreator, _, validatorUtils, validatorWalletCreator, err := deployLegacyRollupCreator(ctx, parentChainReader, deployAuth, maxDataSize, chainSupportsBlobs) + if err != nil { + return nil, fmt.Errorf("error deploying rollup creator: %w", err) + } + + var validatorAddrs []common.Address + for i := uint64(1); i <= authorizeValidators; i++ { + validatorAddrs = append(validatorAddrs, crypto.CreateAddress(validatorWalletCreator, i)) + } + deployParams := rollupgen.RollupCreatorRollupDeploymentParams{ + Config: config, + Validators: validatorAddrs, + MaxDataSize: maxDataSize, + NativeToken: nativeToken, + DeployFactoriesToL2: false, + MaxFeePerGasForRetryables: big.NewInt(0), // needed when utility factories are deployed + BatchPosters: batchPosters, + BatchPosterManager: batchPosterManager, + } + + tx, err := rollupCreator.CreateRollup( + deployAuth, + deployParams, + ) + + if err != nil { + return nil, fmt.Errorf("error submitting create rollup tx: %w", err) + } + receipt, err := parentChainReader.WaitForTxApproval(ctx, tx) + if err != nil { + return nil, fmt.Errorf("error executing create rollup tx: %w", err) + } + info, err := rollupCreator.ParseRollupCreated(*receipt.Logs[len(receipt.Logs)-1]) + if err != nil { + return nil, fmt.Errorf("error parsing rollup created log: %w", err) + } + + return &chaininfo.RollupAddresses{ + Bridge: info.Bridge, + Inbox: info.InboxAddress, + SequencerInbox: info.SequencerInbox, + DeployedAt: receipt.BlockNumber.Uint64(), + Rollup: info.RollupAddress, + NativeToken: nativeToken, + UpgradeExecutor: info.UpgradeExecutor, + ValidatorUtils: validatorUtils, + ValidatorWalletCreator: validatorWalletCreator, + }, nil +} diff --git a/system_tests/batch_poster_test.go b/system_tests/batch_poster_test.go index 2ba3da328e..ffcd6a02be 100644 --- a/system_tests/batch_poster_test.go +++ b/system_tests/batch_poster_test.go @@ -392,7 +392,10 @@ func testBatchPosterDelayBuffer(t *testing.T, delayBufferEnabled bool) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) + builder := NewNodeBuilder(ctx). + DefaultConfig(t, true). + WithBoldContracts(). + WithDelayBufferThreshold(threshold) builder.L2Info.GenerateAccount("User2") builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer cleanup := builder.Build(t) @@ -446,7 +449,10 @@ func TestBatchPosterDelayBufferDontForceNonDelayedMessages(t *testing.T) { defer cancel() const threshold = 100 - builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) + builder := NewNodeBuilder(ctx). + DefaultConfig(t, true). + WithBoldContracts(). + WithDelayBufferThreshold(threshold) builder.L2Info.GenerateAccount("User2") builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer cleanup := builder.Build(t) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 4bbf7c473c..a08d60f470 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -71,10 +71,11 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/offchainlabs/bold/solgen/go/mocksgen" + "github.com/offchainlabs/bold/solgen/go/rollupgen" "github.com/offchainlabs/nitro/arbnode" _ "github.com/offchainlabs/nitro/execution/nodeInterface" "github.com/offchainlabs/nitro/solgen/go/bridgegen" - "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" "github.com/offchainlabs/nitro/statetransfer" @@ -252,6 +253,7 @@ type NodeBuilder struct { l3InitMessage *arbostypes.ParsedInitMessage withProdConfirmPeriodBlocks bool wasmCacheTag uint32 + deployBoldContracts bool delayBufferThreshold uint64 // Created nodes @@ -365,10 +367,15 @@ func (b *NodeBuilder) WithStylusLongTermCache(enabled bool) *NodeBuilder { return b } -// WithDelayBuffer sets the delay-buffer threshold, which is the number of blocks the batch-poster +func (b *NodeBuilder) WithBoldContracts() *NodeBuilder { + b.deployBoldContracts = true + return b +} + +// WithDelayBufferThreshold sets the delay-buffer threshold, which is the number of blocks the batch-poster // is allowed to delay a batch with a delayed message. // Setting the threshold to zero disabled the delay buffer (default behaviour). -func (b *NodeBuilder) WithDelayBuffer(threshold uint64) *NodeBuilder { +func (b *NodeBuilder) WithDelayBufferThreshold(threshold uint64) *NodeBuilder { b.delayBufferThreshold = threshold return b } @@ -422,6 +429,7 @@ func (b *NodeBuilder) BuildL1(t *testing.T) { locator.LatestWasmModuleRoot(), b.withProdConfirmPeriodBlocks, true, + b.deployBoldContracts, b.delayBufferThreshold, ) b.L1.cleanup = func() { requireClose(t, b.L1.Stack) } @@ -526,6 +534,7 @@ func (b *NodeBuilder) BuildL3OnL2(t *testing.T) func() { locator.LatestWasmModuleRoot(), b.l3Config.withProdConfirmPeriodBlocks, false, + false, 0, ) @@ -1270,6 +1279,7 @@ func deployOnParentChain( wasmModuleRoot common.Hash, prodConfirmPeriodBlocks bool, chainSupportsBlobs bool, + deployBoldContracts bool, delayBufferThreshold uint64, ) (*chaininfo.RollupAddresses, *arbostypes.ParsedInitMessage) { parentChainInfo.GenerateAccount("RollupOwner") @@ -1293,24 +1303,62 @@ func deployOnParentChain( parentChainReader.Start(ctx) defer parentChainReader.StopAndWait() - bufferConfig := arbnode.DefaultBufferConfig() - bufferConfig.Threshold = delayBufferThreshold - nativeToken := common.Address{} maxDataSize := big.NewInt(117964) - addresses, err := deploy.DeployOnParentChain( - ctx, - parentChainReader, - &parentChainTransactionOpts, - []common.Address{parentChainInfo.GetAddress("Sequencer")}, - parentChainInfo.GetAddress("RollupOwner"), - 0, - arbnode.GenerateRollupConfig(prodConfirmPeriodBlocks, wasmModuleRoot, parentChainInfo.GetAddress("RollupOwner"), chainConfig, serializedChainConfig, common.Address{}, bufferConfig), - nativeToken, - maxDataSize, - chainSupportsBlobs, - ) + var addresses *chaininfo.RollupAddresses + if deployBoldContracts { + miniStakeValues := []*big.Int{big.NewInt(5), big.NewInt(4), big.NewInt(3), big.NewInt(2), big.NewInt(1)} + opts := deploy.RollupConfigOpts{ + Prod: prodConfirmPeriodBlocks, + WasmModuleRoot: wasmModuleRoot, + RollupOwner: parentChainInfo.GetAddress("RollupOwner"), + ChainConfig: chainConfig, + SerializedChainConfig: serializedChainConfig, + LoserStakeEscrow: parentChainInfo.GetAddress("RollupOwner"), + MiniStakeValues: miniStakeValues, + StakeToken: deployStakeToken(t, ctx, parentChainInfo, parentChainClient), + GenesisExecutionState: rollupgen.AssertionState{ + GlobalState: rollupgen.GlobalState{}, + MachineStatus: 1, + EndHistoryRoot: [32]byte{}, + }, + GenesisInboxCount: big.NewInt(0), + AnyTrustFastConfirmer: common.Address{}, + LayerZeroBlockEdgeHeight: 1 << 5, + LayerZeroBigStepEdgeHeight: 1 << 10, + LayerZeroSmallStepEdgeHeight: 1 << 10, + NumBigStepLevel: 3, + BufferConfig: deploy.DefaultBufferConfig(), + } + opts.BufferConfig.Threshold = delayBufferThreshold + addresses, err = deploy.DeployOnParentChain( + ctx, + parentChainReader, + &parentChainTransactionOpts, + []common.Address{parentChainInfo.GetAddress("Sequencer")}, + parentChainInfo.GetAddress("RollupOwner"), + 0, + deploy.GenerateRollupConfig(&opts), + nativeToken, + maxDataSize, + chainSupportsBlobs, + ) + } else { + addresses, err = deploy.DeployLegacyOnParentChain( + ctx, + parentChainReader, + &parentChainTransactionOpts, + []common.Address{parentChainInfo.GetAddress("Sequencer")}, + parentChainInfo.GetAddress("RollupOwner"), + 0, + deploy.GenerateLegacyRollupConfig(prodConfirmPeriodBlocks, wasmModuleRoot, parentChainInfo.GetAddress("RollupOwner"), chainConfig, serializedChainConfig, common.Address{}), + nativeToken, + maxDataSize, + chainSupportsBlobs, + ) + } Require(t, err) + parentChainInfo.SetContract("Bridge", addresses.Bridge) parentChainInfo.SetContract("SequencerInbox", addresses.SequencerInbox) parentChainInfo.SetContract("Inbox", addresses.Inbox) @@ -1617,6 +1665,25 @@ func getDeadlineTimeout(t *testing.T, defaultTimeout time.Duration) time.Duratio return timeout } +func deployStakeToken(t *testing.T, ctx context.Context, info *BlockchainTestInfo, client *ethclient.Client) common.Address { + transactionOpts := info.GetDefaultTransactOpts("RollupOwner", ctx) + stakeToken, tx, tokenBindings, err := mocksgen.DeployTestWETH9( + &transactionOpts, + client, + "Weth", + "WETH", + ) + Require(t, err) + _, err = EnsureTxSucceeded(ctx, client, tx) + Require(t, err) + transactionOpts.Value = big.NewInt(10000) + tx, err = tokenBindings.Deposit(&transactionOpts) + Require(t, err) + _, err = EnsureTxSucceeded(ctx, client, tx) + Require(t, err) + return stakeToken +} + func deploySimple( t *testing.T, ctx context.Context, auth bind.TransactOpts, client *ethclient.Client, ) (common.Address, *mocksgen.Simple) { diff --git a/system_tests/full_challenge_impl_test.go b/system_tests/full_challenge_impl_test.go index 30b7352892..4d902f87ba 100644 --- a/system_tests/full_challenge_impl_test.go +++ b/system_tests/full_challenge_impl_test.go @@ -215,7 +215,6 @@ func setupSequencerInboxStub(ctx context.Context, t *testing.T, l1Info *Blockcha big.NewInt(117964), reader4844, false, - false, ) Require(t, err) _, err = EnsureTxSucceeded(ctx, l1Client, tx) From b203a3d97fe188ab1fbd3046b9353d06fc1b6ba6 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 26 Nov 2024 16:04:54 -0300 Subject: [PATCH 14/25] Revert "Use BoLD contracts to test delay buffer" This reverts commit b0d586cb4dcc13d414de86eb35958f5bb04be54a. --- arbnode/batch_poster.go | 3 +- arbnode/delay_buffer.go | 2 +- arbnode/node.go | 37 +++ cmd/deploy/deploy.go | 12 +- deploy/deploy.go | 117 ++------- deploy/legacy.go | 321 ----------------------- system_tests/batch_poster_test.go | 10 +- system_tests/common_test.go | 103 ++------ system_tests/full_challenge_impl_test.go | 1 + 9 files changed, 97 insertions(+), 509 deletions(-) delete mode 100644 deploy/legacy.go diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index eb0a98240c..fc1a789db9 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - "github.com/offchainlabs/bold/solgen/go/bridgegen" "github.com/offchainlabs/nitro/arbnode/dataposter" "github.com/offchainlabs/nitro/arbnode/dataposter/storage" "github.com/offchainlabs/nitro/arbnode/redislock" @@ -45,6 +44,7 @@ import ( "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/execution" + "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/blobs" @@ -317,6 +317,7 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e if err = opts.Config().Validate(); err != nil { return nil, err } + // TODO(delaybuffer) use new bridgegen seqInboxABI, err := bridgegen.SequencerInboxMetaData.GetAbi() if err != nil { return nil, err diff --git a/arbnode/delay_buffer.go b/arbnode/delay_buffer.go index ffef7ee828..508fec1b35 100644 --- a/arbnode/delay_buffer.go +++ b/arbnode/delay_buffer.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/offchainlabs/bold/solgen/go/bridgegen" "github.com/offchainlabs/nitro/arbos/arbostypes" + "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/util/headerreader" ) diff --git a/arbnode/node.go b/arbnode/node.go index 7445999fcd..d7d9465205 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -39,6 +39,7 @@ import ( "github.com/offchainlabs/nitro/execution/gethexec" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker" boldstaker "github.com/offchainlabs/nitro/staker/bold" legacystaker "github.com/offchainlabs/nitro/staker/legacy" @@ -52,6 +53,42 @@ import ( "github.com/offchainlabs/nitro/wsbroadcastserver" ) +func DefaultBufferConfig() rollupgen.BufferConfig { + return rollupgen.BufferConfig{ + Threshold: 600, // 1 hour of blocks + Max: 14400, // 2 days of blocks + ReplenishRateInBasis: 500, // 5% + } +} + +func GenerateRollupConfig(prod bool, wasmModuleRoot common.Hash, rollupOwner common.Address, chainConfig *params.ChainConfig, serializedChainConfig []byte, loserStakeEscrow common.Address, bufferConfig rollupgen.BufferConfig) rollupgen.Config { + var confirmPeriod uint64 + if prod { + confirmPeriod = 45818 + } else { + confirmPeriod = 20 + } + return rollupgen.Config{ + ConfirmPeriodBlocks: confirmPeriod, + ExtraChallengeTimeBlocks: 200, + StakeToken: common.Address{}, + BaseStake: big.NewInt(params.Ether), + WasmModuleRoot: wasmModuleRoot, + Owner: rollupOwner, + LoserStakeEscrow: loserStakeEscrow, + ChainId: chainConfig.ChainID, + // TODO could the ChainConfig be just []byte? + ChainConfig: string(serializedChainConfig), + SequencerInboxMaxTimeVariation: rollupgen.ISequencerInboxMaxTimeVariation{ + DelayBlocks: big.NewInt(60 * 60 * 24 / 15), + FutureBlocks: big.NewInt(12), + DelaySeconds: big.NewInt(60 * 60 * 24), + FutureSeconds: big.NewInt(60 * 60), + }, + BufferConfig: bufferConfig, + } +} + type Config struct { Sequencer bool `koanf:"sequencer"` ParentChainReader headerreader.Config `koanf:"parent-chain-reader" reload:"hot"` diff --git a/cmd/deploy/deploy.go b/cmd/deploy/deploy.go index 603539196f..6060c55586 100644 --- a/cmd/deploy/deploy.go +++ b/cmd/deploy/deploy.go @@ -17,6 +17,7 @@ import ( "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/validator/server_common" @@ -25,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/offchainlabs/nitro/arbnode" "github.com/offchainlabs/nitro/cmd/util" deploycode "github.com/offchainlabs/nitro/deploy" ) @@ -60,6 +62,7 @@ func main() { authorizevalidators := flag.Uint64("authorizevalidators", 0, "Number of validators to preemptively authorize") txTimeout := flag.Duration("txtimeout", 10*time.Minute, "Timeout when waiting for a transaction to be included in a block") prod := flag.Bool("prod", false, "Whether to configure the rollup for production or testing") + isDelayBufferable := flag.Bool("delayBufferable", false, "Whether the sequencer-inbox delay buffer is enabled") flag.Parse() l1ChainId := new(big.Int).SetUint64(*l1ChainIdUint) maxDataSize := new(big.Int).SetUint64(*maxDataSizeUint) @@ -169,6 +172,11 @@ func main() { panic(fmt.Errorf("failed to deserialize chain config: %w", err)) } + var bufferConfig rollupgen.BufferConfig + if *isDelayBufferable { + bufferConfig = arbnode.DefaultBufferConfig() + } + arbSys, _ := precompilesgen.NewArbSys(types.ArbSysAddress, l1client) l1Reader, err := headerreader.New(ctx, l1client, func() *headerreader.Config { return &headerReaderConfig }, arbSys) if err != nil { @@ -178,14 +186,14 @@ func main() { defer l1Reader.StopAndWait() nativeToken := common.HexToAddress(*nativeTokenAddressString) - deployedAddresses, err := deploycode.DeployLegacyOnParentChain( + deployedAddresses, err := deploycode.DeployOnParentChain( ctx, l1Reader, l1TransactionOpts, batchPosters, batchPosterManagerAddress, *authorizevalidators, - deploycode.GenerateLegacyRollupConfig(*prod, moduleRoot, ownerAddress, &chainConfig, chainConfigJson, loserEscrowAddress), + arbnode.GenerateRollupConfig(*prod, moduleRoot, ownerAddress, &chainConfig, chainConfigJson, loserEscrowAddress, bufferConfig), nativeToken, maxDataSize, true, diff --git a/deploy/deploy.go b/deploy/deploy.go index 6a71dd9673..858d06db89 100644 --- a/deploy/deploy.go +++ b/deploy/deploy.go @@ -10,89 +10,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/params" - "github.com/offchainlabs/bold/solgen/go/bridgegen" - "github.com/offchainlabs/bold/solgen/go/challengeV2gen" - "github.com/offchainlabs/bold/solgen/go/ospgen" - "github.com/offchainlabs/bold/solgen/go/rollupgen" - "github.com/offchainlabs/bold/solgen/go/yulgen" "github.com/offchainlabs/nitro/cmd/chaininfo" + "github.com/offchainlabs/nitro/solgen/go/bridgegen" + "github.com/offchainlabs/nitro/solgen/go/challengegen" + "github.com/offchainlabs/nitro/solgen/go/ospgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" + "github.com/offchainlabs/nitro/solgen/go/yulgen" "github.com/offchainlabs/nitro/util/headerreader" ) -// lint:require-exhaustive-initialization -type RollupConfigOpts struct { - Prod bool - WasmModuleRoot common.Hash - RollupOwner common.Address - ChainConfig *params.ChainConfig - SerializedChainConfig []byte - LoserStakeEscrow common.Address - MiniStakeValues []*big.Int - StakeToken common.Address - GenesisExecutionState rollupgen.AssertionState - GenesisInboxCount *big.Int - AnyTrustFastConfirmer common.Address - LayerZeroBlockEdgeHeight uint64 - LayerZeroBigStepEdgeHeight uint64 - LayerZeroSmallStepEdgeHeight uint64 - NumBigStepLevel uint8 - BufferConfig rollupgen.BufferConfig -} - -func DefaultBufferConfig() rollupgen.BufferConfig { - return rollupgen.BufferConfig{ - Threshold: 600, // 1 hour of blocks - Max: 14400, // 2 days of blocks - ReplenishRateInBasis: 500, // 5% - } -} - -func GenerateRollupConfig(opts *RollupConfigOpts) rollupgen.Config { - var confirmPeriod uint64 - if opts.Prod { - confirmPeriod = 45818 - } else { - confirmPeriod = 25 - } - - var gracePeriod uint64 - if opts.Prod { - gracePeriod = 14400 - } else { - gracePeriod = 3 - } - - cfg := rollupgen.Config{ - ConfirmPeriodBlocks: confirmPeriod, - StakeToken: opts.StakeToken, - BaseStake: big.NewInt(1), - WasmModuleRoot: opts.WasmModuleRoot, - Owner: opts.RollupOwner, - LoserStakeEscrow: opts.LoserStakeEscrow, - ChainId: opts.ChainConfig.ChainID, - ChainConfig: string(opts.SerializedChainConfig), - MiniStakeValues: opts.MiniStakeValues, - SequencerInboxMaxTimeVariation: rollupgen.ISequencerInboxMaxTimeVariation{ - DelayBlocks: big.NewInt(60 * 60 * 24 / 15), - FutureBlocks: big.NewInt(12), - DelaySeconds: big.NewInt(60 * 60 * 24), - FutureSeconds: big.NewInt(60 * 60), - }, - LayerZeroBlockEdgeHeight: new(big.Int).SetUint64(opts.LayerZeroBlockEdgeHeight), - LayerZeroBigStepEdgeHeight: new(big.Int).SetUint64(opts.LayerZeroBigStepEdgeHeight), - LayerZeroSmallStepEdgeHeight: new(big.Int).SetUint64(opts.LayerZeroSmallStepEdgeHeight), - GenesisAssertionState: opts.GenesisExecutionState, - GenesisInboxCount: opts.GenesisInboxCount, - AnyTrustFastConfirmer: opts.AnyTrustFastConfirmer, - NumBigStepLevel: opts.NumBigStepLevel, - ChallengeGracePeriodBlocks: gracePeriod, - BufferConfig: opts.BufferConfig, - } - return cfg -} - func andTxSucceeded(ctx context.Context, parentChainReader *headerreader.HeaderReader, tx *types.Transaction, err error) error { if err != nil { return fmt.Errorf("error submitting tx: %w", err) @@ -240,7 +167,7 @@ func deployChallengeFactory(ctx context.Context, parentChainReader *headerreader return common.Address{}, common.Address{}, fmt.Errorf("ospHostIo deploy error: %w", err) } - challengeManagerAddr, tx, _, err := challengeV2gen.DeployEdgeChallengeManager(auth, client) + challengeManagerAddr, tx, _, err := challengegen.DeployChallengeManager(auth, client) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { return common.Address{}, common.Address{}, fmt.Errorf("challenge manager deploy error: %w", err) @@ -255,51 +182,57 @@ func deployChallengeFactory(ctx context.Context, parentChainReader *headerreader return ospEntryAddr, challengeManagerAddr, nil } -func deployRollupCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (*rollupgen.RollupCreator, common.Address, common.Address, error) { +func deployRollupCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (*rollupgen.RollupCreator, common.Address, common.Address, common.Address, error) { bridgeCreator, err := deployBridgeCreator(ctx, parentChainReader, auth, maxDataSize, chainSupportsBlobs) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) } ospEntryAddr, challengeManagerAddr, err := deployChallengeFactory(ctx, parentChainReader, auth) if err != nil { - return nil, common.Address{}, common.Address{}, err + return nil, common.Address{}, common.Address{}, common.Address{}, err } rollupAdminLogic, tx, _, err := rollupgen.DeployRollupAdminLogic(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup admin logic deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup admin logic deploy error: %w", err) } rollupUserLogic, tx, _, err := rollupgen.DeployRollupUserLogic(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup user logic deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup user logic deploy error: %w", err) } rollupCreatorAddress, tx, rollupCreator, err := rollupgen.DeployRollupCreator(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup creator deploy error: %w", err) } upgradeExecutor, tx, _, err := upgrade_executorgen.DeployUpgradeExecutor(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("upgrade executor deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("upgrade executor deploy error: %w", err) + } + + validatorUtils, tx, _, err := rollupgen.DeployValidatorUtils(auth, parentChainReader.Client()) + err = andTxSucceeded(ctx, parentChainReader, tx, err) + if err != nil { + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator utils deploy error: %w", err) } validatorWalletCreator, tx, _, err := rollupgen.DeployValidatorWalletCreator(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("validator wallet creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator wallet creator deploy error: %w", err) } l2FactoriesDeployHelper, tx, _, err := rollupgen.DeployDeployHelper(auth, parentChainReader.Client()) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("deploy helper creator deploy error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("deploy helper creator deploy error: %w", err) } tx, err = rollupCreator.SetTemplates( @@ -310,15 +243,16 @@ func deployRollupCreator(ctx context.Context, parentChainReader *headerreader.He rollupAdminLogic, rollupUserLogic, upgradeExecutor, + validatorUtils, validatorWalletCreator, l2FactoriesDeployHelper, ) err = andTxSucceeded(ctx, parentChainReader, tx, err) if err != nil { - return nil, common.Address{}, common.Address{}, fmt.Errorf("rollup set template error: %w", err) + return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup set template error: %w", err) } - return rollupCreator, rollupCreatorAddress, validatorWalletCreator, nil + return rollupCreator, rollupCreatorAddress, validatorUtils, validatorWalletCreator, nil } func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.HeaderReader, deployAuth *bind.TransactOpts, batchPosters []common.Address, batchPosterManager common.Address, authorizeValidators uint64, config rollupgen.Config, nativeToken common.Address, maxDataSize *big.Int, chainSupportsBlobs bool) (*chaininfo.RollupAddresses, error) { @@ -326,7 +260,7 @@ func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.He return nil, errors.New("no machine specified") } - rollupCreator, _, validatorWalletCreator, err := deployRollupCreator(ctx, parentChainReader, deployAuth, maxDataSize, chainSupportsBlobs) + rollupCreator, _, validatorUtils, validatorWalletCreator, err := deployRollupCreator(ctx, parentChainReader, deployAuth, maxDataSize, chainSupportsBlobs) if err != nil { return nil, fmt.Errorf("error deploying rollup creator: %w", err) } @@ -371,6 +305,7 @@ func DeployOnParentChain(ctx context.Context, parentChainReader *headerreader.He Rollup: info.RollupAddress, NativeToken: nativeToken, UpgradeExecutor: info.UpgradeExecutor, + ValidatorUtils: validatorUtils, ValidatorWalletCreator: validatorWalletCreator, }, nil } diff --git a/deploy/legacy.go b/deploy/legacy.go deleted file mode 100644 index 908052ae08..0000000000 --- a/deploy/legacy.go +++ /dev/null @@ -1,321 +0,0 @@ -package deploy - -import ( - "context" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/params" - "github.com/offchainlabs/nitro/cmd/chaininfo" - "github.com/offchainlabs/nitro/solgen/go/bridgegen" - "github.com/offchainlabs/nitro/solgen/go/challengegen" - "github.com/offchainlabs/nitro/solgen/go/ospgen" - "github.com/offchainlabs/nitro/solgen/go/rollupgen" - "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" - "github.com/offchainlabs/nitro/solgen/go/yulgen" - "github.com/offchainlabs/nitro/util/headerreader" -) - -func GenerateLegacyRollupConfig( - prod bool, - wasmModuleRoot common.Hash, - rollupOwner common.Address, - chainConfig *params.ChainConfig, - serializedChainConfig []byte, - loserStakeEscrow common.Address, -) rollupgen.Config { - var confirmPeriod uint64 - if prod { - confirmPeriod = 45818 - } else { - confirmPeriod = 20 - } - return rollupgen.Config{ - ConfirmPeriodBlocks: confirmPeriod, - ExtraChallengeTimeBlocks: 200, - StakeToken: common.Address{}, - BaseStake: big.NewInt(params.Ether), - WasmModuleRoot: wasmModuleRoot, - Owner: rollupOwner, - LoserStakeEscrow: loserStakeEscrow, - ChainId: chainConfig.ChainID, - // TODO could the ChainConfig be just []byte? - ChainConfig: string(serializedChainConfig), - SequencerInboxMaxTimeVariation: rollupgen.ISequencerInboxMaxTimeVariation{ - DelayBlocks: big.NewInt(60 * 60 * 24 / 15), - FutureBlocks: big.NewInt(12), - DelaySeconds: big.NewInt(60 * 60 * 24), - FutureSeconds: big.NewInt(60 * 60), - }, - } -} - -func deployLegacyBridgeCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (common.Address, error) { - client := parentChainReader.Client() - - /// deploy eth based templates - bridgeTemplate, tx, _, err := bridgegen.DeployBridge(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("bridge deploy error: %w", err) - } - - var reader4844 common.Address - if chainSupportsBlobs { - reader4844, tx, _, err = yulgen.DeployReader4844(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("blob basefee reader deploy error: %w", err) - } - } - seqInboxTemplateEthBased, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, false) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("sequencer inbox eth based deploy error: %w", err) - } - seqInboxTemplateERC20Based, tx, _, err := bridgegen.DeploySequencerInbox(auth, client, maxDataSize, reader4844, true) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("sequencer inbox erc20 based deploy error: %w", err) - } - - inboxTemplate, tx, _, err := bridgegen.DeployInbox(auth, client, maxDataSize) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("inbox deploy error: %w", err) - } - - rollupEventBridgeTemplate, tx, _, err := rollupgen.DeployRollupEventInbox(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("rollup event bridge deploy error: %w", err) - } - - outboxTemplate, tx, _, err := bridgegen.DeployOutbox(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("outbox deploy error: %w", err) - } - - ethBasedTemplates := rollupgen.BridgeCreatorBridgeContracts{ - Bridge: bridgeTemplate, - SequencerInbox: seqInboxTemplateEthBased, - Inbox: inboxTemplate, - RollupEventInbox: rollupEventBridgeTemplate, - Outbox: outboxTemplate, - } - - /// deploy ERC20 based templates - erc20BridgeTemplate, tx, _, err := bridgegen.DeployERC20Bridge(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("bridge deploy error: %w", err) - } - - erc20InboxTemplate, tx, _, err := bridgegen.DeployERC20Inbox(auth, client, maxDataSize) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("inbox deploy error: %w", err) - } - - erc20RollupEventBridgeTemplate, tx, _, err := rollupgen.DeployERC20RollupEventInbox(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("rollup event bridge deploy error: %w", err) - } - - erc20OutboxTemplate, tx, _, err := bridgegen.DeployERC20Outbox(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("outbox deploy error: %w", err) - } - - erc20BasedTemplates := rollupgen.BridgeCreatorBridgeContracts{ - Bridge: erc20BridgeTemplate, - SequencerInbox: seqInboxTemplateERC20Based, - Inbox: erc20InboxTemplate, - RollupEventInbox: erc20RollupEventBridgeTemplate, - Outbox: erc20OutboxTemplate, - } - - bridgeCreatorAddr, tx, _, err := rollupgen.DeployBridgeCreator(auth, client, ethBasedTemplates, erc20BasedTemplates) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) - } - - return bridgeCreatorAddr, nil -} - -func deployLegacyChallengeFactory(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts) (common.Address, common.Address, error) { - client := parentChainReader.Client() - osp0, tx, _, err := ospgen.DeployOneStepProver0(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, common.Address{}, fmt.Errorf("osp0 deploy error: %w", err) - } - - ospMem, tx, _, err := ospgen.DeployOneStepProverMemory(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, common.Address{}, fmt.Errorf("ospMemory deploy error: %w", err) - } - - ospMath, tx, _, err := ospgen.DeployOneStepProverMath(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, common.Address{}, fmt.Errorf("ospMath deploy error: %w", err) - } - - ospHostIo, tx, _, err := ospgen.DeployOneStepProverHostIo(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, common.Address{}, fmt.Errorf("ospHostIo deploy error: %w", err) - } - - challengeManagerAddr, tx, _, err := challengegen.DeployChallengeManager(auth, client) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, common.Address{}, fmt.Errorf("challenge manager deploy error: %w", err) - } - - ospEntryAddr, tx, _, err := ospgen.DeployOneStepProofEntry(auth, client, osp0, ospMem, ospMath, ospHostIo) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return common.Address{}, common.Address{}, fmt.Errorf("ospEntry deploy error: %w", err) - } - - return ospEntryAddr, challengeManagerAddr, nil -} - -func deployLegacyRollupCreator(ctx context.Context, parentChainReader *headerreader.HeaderReader, auth *bind.TransactOpts, maxDataSize *big.Int, chainSupportsBlobs bool) (*rollupgen.RollupCreator, common.Address, common.Address, common.Address, error) { - bridgeCreator, err := deployLegacyBridgeCreator(ctx, parentChainReader, auth, maxDataSize, chainSupportsBlobs) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("bridge creator deploy error: %w", err) - } - - ospEntryAddr, challengeManagerAddr, err := deployLegacyChallengeFactory(ctx, parentChainReader, auth) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, err - } - - rollupAdminLogic, tx, _, err := rollupgen.DeployRollupAdminLogic(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup admin logic deploy error: %w", err) - } - - rollupUserLogic, tx, _, err := rollupgen.DeployRollupUserLogic(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup user logic deploy error: %w", err) - } - - rollupCreatorAddress, tx, rollupCreator, err := rollupgen.DeployRollupCreator(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup creator deploy error: %w", err) - } - - upgradeExecutor, tx, _, err := upgrade_executorgen.DeployUpgradeExecutor(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("upgrade executor deploy error: %w", err) - } - - validatorUtils, tx, _, err := rollupgen.DeployValidatorUtils(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator utils deploy error: %w", err) - } - - validatorWalletCreator, tx, _, err := rollupgen.DeployValidatorWalletCreator(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("validator wallet creator deploy error: %w", err) - } - - l2FactoriesDeployHelper, tx, _, err := rollupgen.DeployDeployHelper(auth, parentChainReader.Client()) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("deploy helper creator deploy error: %w", err) - } - - tx, err = rollupCreator.SetTemplates( - auth, - bridgeCreator, - ospEntryAddr, - challengeManagerAddr, - rollupAdminLogic, - rollupUserLogic, - upgradeExecutor, - validatorUtils, - validatorWalletCreator, - l2FactoriesDeployHelper, - ) - err = andTxSucceeded(ctx, parentChainReader, tx, err) - if err != nil { - return nil, common.Address{}, common.Address{}, common.Address{}, fmt.Errorf("rollup set template error: %w", err) - } - - return rollupCreator, rollupCreatorAddress, validatorUtils, validatorWalletCreator, nil -} - -func DeployLegacyOnParentChain(ctx context.Context, parentChainReader *headerreader.HeaderReader, deployAuth *bind.TransactOpts, batchPosters []common.Address, batchPosterManager common.Address, authorizeValidators uint64, config rollupgen.Config, nativeToken common.Address, maxDataSize *big.Int, chainSupportsBlobs bool) (*chaininfo.RollupAddresses, error) { - if config.WasmModuleRoot == (common.Hash{}) { - return nil, errors.New("no machine specified") - } - - rollupCreator, _, validatorUtils, validatorWalletCreator, err := deployLegacyRollupCreator(ctx, parentChainReader, deployAuth, maxDataSize, chainSupportsBlobs) - if err != nil { - return nil, fmt.Errorf("error deploying rollup creator: %w", err) - } - - var validatorAddrs []common.Address - for i := uint64(1); i <= authorizeValidators; i++ { - validatorAddrs = append(validatorAddrs, crypto.CreateAddress(validatorWalletCreator, i)) - } - deployParams := rollupgen.RollupCreatorRollupDeploymentParams{ - Config: config, - Validators: validatorAddrs, - MaxDataSize: maxDataSize, - NativeToken: nativeToken, - DeployFactoriesToL2: false, - MaxFeePerGasForRetryables: big.NewInt(0), // needed when utility factories are deployed - BatchPosters: batchPosters, - BatchPosterManager: batchPosterManager, - } - - tx, err := rollupCreator.CreateRollup( - deployAuth, - deployParams, - ) - - if err != nil { - return nil, fmt.Errorf("error submitting create rollup tx: %w", err) - } - receipt, err := parentChainReader.WaitForTxApproval(ctx, tx) - if err != nil { - return nil, fmt.Errorf("error executing create rollup tx: %w", err) - } - info, err := rollupCreator.ParseRollupCreated(*receipt.Logs[len(receipt.Logs)-1]) - if err != nil { - return nil, fmt.Errorf("error parsing rollup created log: %w", err) - } - - return &chaininfo.RollupAddresses{ - Bridge: info.Bridge, - Inbox: info.InboxAddress, - SequencerInbox: info.SequencerInbox, - DeployedAt: receipt.BlockNumber.Uint64(), - Rollup: info.RollupAddress, - NativeToken: nativeToken, - UpgradeExecutor: info.UpgradeExecutor, - ValidatorUtils: validatorUtils, - ValidatorWalletCreator: validatorWalletCreator, - }, nil -} diff --git a/system_tests/batch_poster_test.go b/system_tests/batch_poster_test.go index ffcd6a02be..2ba3da328e 100644 --- a/system_tests/batch_poster_test.go +++ b/system_tests/batch_poster_test.go @@ -392,10 +392,7 @@ func testBatchPosterDelayBuffer(t *testing.T, delayBufferEnabled bool) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx). - DefaultConfig(t, true). - WithBoldContracts(). - WithDelayBufferThreshold(threshold) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) builder.L2Info.GenerateAccount("User2") builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer cleanup := builder.Build(t) @@ -449,10 +446,7 @@ func TestBatchPosterDelayBufferDontForceNonDelayedMessages(t *testing.T) { defer cancel() const threshold = 100 - builder := NewNodeBuilder(ctx). - DefaultConfig(t, true). - WithBoldContracts(). - WithDelayBufferThreshold(threshold) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDelayBuffer(threshold) builder.L2Info.GenerateAccount("User2") builder.nodeConfig.BatchPoster.MaxDelay = time.Hour // set high max-delay so we can test the delay buffer cleanup := builder.Build(t) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index a08d60f470..4bbf7c473c 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -71,11 +71,10 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "github.com/offchainlabs/bold/solgen/go/mocksgen" - "github.com/offchainlabs/bold/solgen/go/rollupgen" "github.com/offchainlabs/nitro/arbnode" _ "github.com/offchainlabs/nitro/execution/nodeInterface" "github.com/offchainlabs/nitro/solgen/go/bridgegen" + "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" "github.com/offchainlabs/nitro/solgen/go/upgrade_executorgen" "github.com/offchainlabs/nitro/statetransfer" @@ -253,7 +252,6 @@ type NodeBuilder struct { l3InitMessage *arbostypes.ParsedInitMessage withProdConfirmPeriodBlocks bool wasmCacheTag uint32 - deployBoldContracts bool delayBufferThreshold uint64 // Created nodes @@ -367,15 +365,10 @@ func (b *NodeBuilder) WithStylusLongTermCache(enabled bool) *NodeBuilder { return b } -func (b *NodeBuilder) WithBoldContracts() *NodeBuilder { - b.deployBoldContracts = true - return b -} - -// WithDelayBufferThreshold sets the delay-buffer threshold, which is the number of blocks the batch-poster +// WithDelayBuffer sets the delay-buffer threshold, which is the number of blocks the batch-poster // is allowed to delay a batch with a delayed message. // Setting the threshold to zero disabled the delay buffer (default behaviour). -func (b *NodeBuilder) WithDelayBufferThreshold(threshold uint64) *NodeBuilder { +func (b *NodeBuilder) WithDelayBuffer(threshold uint64) *NodeBuilder { b.delayBufferThreshold = threshold return b } @@ -429,7 +422,6 @@ func (b *NodeBuilder) BuildL1(t *testing.T) { locator.LatestWasmModuleRoot(), b.withProdConfirmPeriodBlocks, true, - b.deployBoldContracts, b.delayBufferThreshold, ) b.L1.cleanup = func() { requireClose(t, b.L1.Stack) } @@ -534,7 +526,6 @@ func (b *NodeBuilder) BuildL3OnL2(t *testing.T) func() { locator.LatestWasmModuleRoot(), b.l3Config.withProdConfirmPeriodBlocks, false, - false, 0, ) @@ -1279,7 +1270,6 @@ func deployOnParentChain( wasmModuleRoot common.Hash, prodConfirmPeriodBlocks bool, chainSupportsBlobs bool, - deployBoldContracts bool, delayBufferThreshold uint64, ) (*chaininfo.RollupAddresses, *arbostypes.ParsedInitMessage) { parentChainInfo.GenerateAccount("RollupOwner") @@ -1303,62 +1293,24 @@ func deployOnParentChain( parentChainReader.Start(ctx) defer parentChainReader.StopAndWait() + bufferConfig := arbnode.DefaultBufferConfig() + bufferConfig.Threshold = delayBufferThreshold + nativeToken := common.Address{} maxDataSize := big.NewInt(117964) - var addresses *chaininfo.RollupAddresses - if deployBoldContracts { - miniStakeValues := []*big.Int{big.NewInt(5), big.NewInt(4), big.NewInt(3), big.NewInt(2), big.NewInt(1)} - opts := deploy.RollupConfigOpts{ - Prod: prodConfirmPeriodBlocks, - WasmModuleRoot: wasmModuleRoot, - RollupOwner: parentChainInfo.GetAddress("RollupOwner"), - ChainConfig: chainConfig, - SerializedChainConfig: serializedChainConfig, - LoserStakeEscrow: parentChainInfo.GetAddress("RollupOwner"), - MiniStakeValues: miniStakeValues, - StakeToken: deployStakeToken(t, ctx, parentChainInfo, parentChainClient), - GenesisExecutionState: rollupgen.AssertionState{ - GlobalState: rollupgen.GlobalState{}, - MachineStatus: 1, - EndHistoryRoot: [32]byte{}, - }, - GenesisInboxCount: big.NewInt(0), - AnyTrustFastConfirmer: common.Address{}, - LayerZeroBlockEdgeHeight: 1 << 5, - LayerZeroBigStepEdgeHeight: 1 << 10, - LayerZeroSmallStepEdgeHeight: 1 << 10, - NumBigStepLevel: 3, - BufferConfig: deploy.DefaultBufferConfig(), - } - opts.BufferConfig.Threshold = delayBufferThreshold - addresses, err = deploy.DeployOnParentChain( - ctx, - parentChainReader, - &parentChainTransactionOpts, - []common.Address{parentChainInfo.GetAddress("Sequencer")}, - parentChainInfo.GetAddress("RollupOwner"), - 0, - deploy.GenerateRollupConfig(&opts), - nativeToken, - maxDataSize, - chainSupportsBlobs, - ) - } else { - addresses, err = deploy.DeployLegacyOnParentChain( - ctx, - parentChainReader, - &parentChainTransactionOpts, - []common.Address{parentChainInfo.GetAddress("Sequencer")}, - parentChainInfo.GetAddress("RollupOwner"), - 0, - deploy.GenerateLegacyRollupConfig(prodConfirmPeriodBlocks, wasmModuleRoot, parentChainInfo.GetAddress("RollupOwner"), chainConfig, serializedChainConfig, common.Address{}), - nativeToken, - maxDataSize, - chainSupportsBlobs, - ) - } + addresses, err := deploy.DeployOnParentChain( + ctx, + parentChainReader, + &parentChainTransactionOpts, + []common.Address{parentChainInfo.GetAddress("Sequencer")}, + parentChainInfo.GetAddress("RollupOwner"), + 0, + arbnode.GenerateRollupConfig(prodConfirmPeriodBlocks, wasmModuleRoot, parentChainInfo.GetAddress("RollupOwner"), chainConfig, serializedChainConfig, common.Address{}, bufferConfig), + nativeToken, + maxDataSize, + chainSupportsBlobs, + ) Require(t, err) - parentChainInfo.SetContract("Bridge", addresses.Bridge) parentChainInfo.SetContract("SequencerInbox", addresses.SequencerInbox) parentChainInfo.SetContract("Inbox", addresses.Inbox) @@ -1665,25 +1617,6 @@ func getDeadlineTimeout(t *testing.T, defaultTimeout time.Duration) time.Duratio return timeout } -func deployStakeToken(t *testing.T, ctx context.Context, info *BlockchainTestInfo, client *ethclient.Client) common.Address { - transactionOpts := info.GetDefaultTransactOpts("RollupOwner", ctx) - stakeToken, tx, tokenBindings, err := mocksgen.DeployTestWETH9( - &transactionOpts, - client, - "Weth", - "WETH", - ) - Require(t, err) - _, err = EnsureTxSucceeded(ctx, client, tx) - Require(t, err) - transactionOpts.Value = big.NewInt(10000) - tx, err = tokenBindings.Deposit(&transactionOpts) - Require(t, err) - _, err = EnsureTxSucceeded(ctx, client, tx) - Require(t, err) - return stakeToken -} - func deploySimple( t *testing.T, ctx context.Context, auth bind.TransactOpts, client *ethclient.Client, ) (common.Address, *mocksgen.Simple) { diff --git a/system_tests/full_challenge_impl_test.go b/system_tests/full_challenge_impl_test.go index 4d902f87ba..30b7352892 100644 --- a/system_tests/full_challenge_impl_test.go +++ b/system_tests/full_challenge_impl_test.go @@ -215,6 +215,7 @@ func setupSequencerInboxStub(ctx context.Context, t *testing.T, l1Info *Blockcha big.NewInt(117964), reader4844, false, + false, ) Require(t, err) _, err = EnsureTxSucceeded(ctx, l1Client, tx) From 2264d01d4f72d665014047a38e1d742daf22e8ee Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 26 Nov 2024 18:50:20 -0300 Subject: [PATCH 15/25] Remove completed TODO --- arbnode/batch_poster.go | 1 - 1 file changed, 1 deletion(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index b1c914a2f2..1ffe9e3540 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -322,7 +322,6 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e if err = opts.Config().Validate(); err != nil { return nil, err } - // TODO(delaybuffer) use new bridgegen seqInboxABI, err := bridgegen.SequencerInboxMetaData.GetAbi() if err != nil { return nil, err From fb34a9f3475ae2500bbb7914d4f8924160176abb Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Tue, 26 Nov 2024 19:07:56 -0300 Subject: [PATCH 16/25] Fix comment --- system_tests/common_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 53d3f1c62e..1ec0e6226e 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -1331,8 +1331,8 @@ func deployOnParentChain( EndHistoryRoot: [32]byte{}, } bufferConfig := rollupgen.BufferConfig{ - Threshold: delayBufferThreshold, // in seconds - Max: 14400, // in secods; 2 days of blocks + Threshold: delayBufferThreshold, // number of blocks + Max: 14400, // 2 days of blocks ReplenishRateInBasis: 500, // 5% } cfg := rollupgen.Config{ From 1665692ff9b421a9a690e9f8227b56b31d0cbff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20FP?= <105675159+TucksonDev@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:11:34 +0000 Subject: [PATCH 17/25] Update precompiles/ArbAggregator.go Co-authored-by: Joshua Colvin --- precompiles/ArbAggregator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompiles/ArbAggregator.go b/precompiles/ArbAggregator.go index 00e6c3d2cc..cee395189c 100644 --- a/precompiles/ArbAggregator.go +++ b/precompiles/ArbAggregator.go @@ -36,7 +36,7 @@ func (con ArbAggregator) GetBatchPosters(c ctx, evm mech) ([]addr, error) { return c.State.L1PricingState().BatchPosterTable().AllPosters(65536) } -// Adds newBatchPoster as a batch poster +// Adds additional batch poster address func (con ArbAggregator) AddBatchPoster(c ctx, evm mech, newBatchPoster addr) error { isOwner, err := c.State.ChainOwners().IsMember(c.caller) if err != nil { From 70edf0c14fedad417030890dbc9b8627deb082eb Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 11 Dec 2024 11:39:19 -0700 Subject: [PATCH 18/25] Add bold stake token to sepolia chain info --- cmd/chaininfo/arbitrum_chain_info.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/chaininfo/arbitrum_chain_info.json b/cmd/chaininfo/arbitrum_chain_info.json index fcfbb6e26a..d0da391cf8 100644 --- a/cmd/chaininfo/arbitrum_chain_info.json +++ b/cmd/chaininfo/arbitrum_chain_info.json @@ -247,6 +247,7 @@ "rollup": "0xd80810638dbDF9081b72C1B33c65375e807281C8", "validator-utils": "0x1f6860C3cac255fFFa72B7410b1183c3a0D261e0", "validator-wallet-creator": "0x894fC71fA0A666352824EC954B401573C861D664", + "stake-token": "0xefb383126640fe4a760010c6e59c397d2b6c7141", "deployed-at": 4139226 } }, From cabd1fcacdc3bc143df7924b7d816243490c66fe Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 11 Dec 2024 13:33:55 -0700 Subject: [PATCH 19/25] Remove probably leftover println --- validator/server_arb/validator_spawner.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validator/server_arb/validator_spawner.go b/validator/server_arb/validator_spawner.go index 76c19dc8f2..4c74bca695 100644 --- a/validator/server_arb/validator_spawner.go +++ b/validator/server_arb/validator_spawner.go @@ -215,9 +215,8 @@ func (v *ArbitratorSpawner) execute( } func (v *ArbitratorSpawner) Launch(entry *validator.ValidationInput, moduleRoot common.Hash) validator.ValidationRun { - println("LAUCHING ARBITRATOR VALIDATION") v.count.Add(1) - promise := stopwaiter.LaunchPromiseThread[validator.GoGlobalState](v, func(ctx context.Context) (validator.GoGlobalState, error) { + promise := stopwaiter.LaunchPromiseThread(v, func(ctx context.Context) (validator.GoGlobalState, error) { defer v.count.Add(-1) return v.execute(ctx, entry, moduleRoot) }) From 0afaf50119b4a9b174b8e09bf4373f011dfd530a Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 11 Dec 2024 20:15:25 -0700 Subject: [PATCH 20/25] Deduplicate arbitrator RustBytes types --- arbitrator/prover/src/lib.rs | 79 ++++++++++++++++++++++------ arbitrator/stylus/src/evm_api.rs | 3 +- arbitrator/stylus/src/lib.rs | 90 ++++++++------------------------ arbos/programs/native.go | 2 +- validator/server_arb/machine.go | 7 +-- 5 files changed, 91 insertions(+), 90 deletions(-) diff --git a/arbitrator/prover/src/lib.rs b/arbitrator/prover/src/lib.rs index bc2bd4bc48..a147786086 100644 --- a/arbitrator/prover/src/lib.rs +++ b/arbitrator/prover/src/lib.rs @@ -36,6 +36,7 @@ use once_cell::sync::OnceCell; use static_assertions::const_assert_eq; use std::{ ffi::CStr, + marker::PhantomData, num::NonZeroUsize, os::raw::{c_char, c_int}, path::Path, @@ -59,11 +60,67 @@ pub struct CByteArray { } #[repr(C)] -#[derive(Clone, Copy)] -pub struct RustByteArray { +pub struct RustSlice<'a> { + pub ptr: *const u8, + pub len: usize, + pub phantom: PhantomData<&'a [u8]>, +} + +impl<'a> RustSlice<'a> { + pub fn new(slice: &'a [u8]) -> Self { + if slice.is_empty() { + return Self { + ptr: ptr::null(), + len: 0, + phantom: PhantomData, + }; + } + Self { + ptr: slice.as_ptr(), + len: slice.len(), + phantom: PhantomData, + } + } +} + +#[repr(C)] +pub struct RustBytes { pub ptr: *mut u8, pub len: usize, - pub capacity: usize, + pub cap: usize, +} + +impl RustBytes { + pub unsafe fn into_vec(self) -> Vec { + Vec::from_raw_parts(self.ptr, self.len, self.cap) + } + + pub unsafe fn write(&mut self, mut vec: Vec) { + if vec.capacity() == 0 { + *self = RustBytes { + ptr: ptr::null_mut(), + len: 0, + cap: 0, + }; + return; + } + self.ptr = vec.as_mut_ptr(); + self.len = vec.len(); + self.cap = vec.capacity(); + std::mem::forget(vec); + } +} + +/// Frees the vector. Does nothing when the vector is null. +/// +/// # Safety +/// +/// Must only be called once per vec. +#[no_mangle] +pub unsafe extern "C" fn free_rust_bytes(vec: RustBytes) { + if !vec.ptr.is_null() { + drop(vec.into_vec()) + } } #[no_mangle] @@ -410,18 +467,6 @@ pub unsafe extern "C" fn arbitrator_module_root(mach: *mut Machine) -> Bytes32 { #[no_mangle] #[cfg(feature = "native")] -pub unsafe extern "C" fn arbitrator_gen_proof(mach: *mut Machine) -> RustByteArray { - let mut proof = (*mach).serialize_proof(); - let ret = RustByteArray { - ptr: proof.as_mut_ptr(), - len: proof.len(), - capacity: proof.capacity(), - }; - std::mem::forget(proof); - ret -} - -#[no_mangle] -pub unsafe extern "C" fn arbitrator_free_proof(proof: RustByteArray) { - drop(Vec::from_raw_parts(proof.ptr, proof.len, proof.capacity)) +pub unsafe extern "C" fn arbitrator_gen_proof(mach: *mut Machine, out: *mut RustBytes) { + (*out).write((*mach).serialize_proof()); } diff --git a/arbitrator/stylus/src/evm_api.rs b/arbitrator/stylus/src/evm_api.rs index 0dd27e3f8c..7aa605dfe7 100644 --- a/arbitrator/stylus/src/evm_api.rs +++ b/arbitrator/stylus/src/evm_api.rs @@ -1,11 +1,12 @@ // Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use crate::{GoSliceData, RustSlice}; +use crate::GoSliceData; use arbutil::evm::{ api::{EvmApiMethod, Gas, EVM_API_METHOD_REQ_OFFSET}, req::RequestHandler, }; +use prover::RustSlice; #[repr(C)] pub struct NativeRequestHandler { diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index e7f10c2400..c73c4b2c2e 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -15,9 +15,12 @@ use cache::{deserialize_module, CacheMetrics, InitCache}; use evm_api::NativeRequestHandler; use eyre::ErrReport; use native::NativeInstance; -use prover::programs::{prelude::*, StylusData}; +use prover::{ + programs::{prelude::*, StylusData}, + RustBytes, +}; use run::RunProgram; -use std::{marker::PhantomData, mem, ptr}; +use std::ptr; use target_cache::{target_cache_get, target_cache_set}; pub use brotli; @@ -76,52 +79,15 @@ impl DataReader for GoSliceData { } } -#[repr(C)] -pub struct RustSlice<'a> { - ptr: *const u8, - len: usize, - phantom: PhantomData<&'a [u8]>, -} - -impl<'a> RustSlice<'a> { - fn new(slice: &'a [u8]) -> Self { - Self { - ptr: slice.as_ptr(), - len: slice.len(), - phantom: PhantomData, - } - } -} - -#[repr(C)] -pub struct RustBytes { - ptr: *mut u8, - len: usize, - cap: usize, +unsafe fn write_err(output: &mut RustBytes, err: ErrReport) -> UserOutcomeKind { + output.write(err.debug_bytes()); + UserOutcomeKind::Failure } -impl RustBytes { - unsafe fn into_vec(self) -> Vec { - Vec::from_raw_parts(self.ptr, self.len, self.cap) - } - - unsafe fn write(&mut self, mut vec: Vec) { - self.ptr = vec.as_mut_ptr(); - self.len = vec.len(); - self.cap = vec.capacity(); - mem::forget(vec); - } - - unsafe fn write_err(&mut self, err: ErrReport) -> UserOutcomeKind { - self.write(err.debug_bytes()); - UserOutcomeKind::Failure - } - - unsafe fn write_outcome(&mut self, outcome: UserOutcome) -> UserOutcomeKind { - let (status, outs) = outcome.into_data(); - self.write(outs); - status - } +unsafe fn write_outcome(output: &mut RustBytes, outcome: UserOutcome) -> UserOutcomeKind { + let (status, outs) = outcome.into_data(); + output.write(outs); + status } /// "activates" a user wasm. @@ -164,7 +130,7 @@ pub unsafe extern "C" fn stylus_activate( gas, ) { Ok(val) => val, - Err(err) => return output.write_err(err), + Err(err) => return write_err(output, err), }; *module_hash = module.hash(); @@ -194,16 +160,16 @@ pub unsafe extern "C" fn stylus_compile( let output = &mut *output; let name = match String::from_utf8(name.slice().to_vec()) { Ok(val) => val, - Err(err) => return output.write_err(err.into()), + Err(err) => return write_err(output, err.into()), }; let target = match target_cache_get(&name) { Ok(val) => val, - Err(err) => return output.write_err(err), + Err(err) => return write_err(output, err), }; let asm = match native::compile(wasm, version, debug, target) { Ok(val) => val, - Err(err) => return output.write_err(err), + Err(err) => return write_err(output, err), }; output.write(asm); @@ -218,7 +184,7 @@ pub unsafe extern "C" fn wat_to_wasm(wat: GoSliceData, output: *mut RustBytes) - let output = &mut *output; let wasm = match wasmer::wat2wasm(wat.slice()) { Ok(val) => val, - Err(err) => return output.write_err(err.into()), + Err(err) => return write_err(output, err.into()), }; output.write(wasm.into_owned()); UserOutcomeKind::Success @@ -241,16 +207,16 @@ pub unsafe extern "C" fn stylus_target_set( let output = &mut *output; let name = match String::from_utf8(name.slice().to_vec()) { Ok(val) => val, - Err(err) => return output.write_err(err.into()), + Err(err) => return write_err(output, err.into()), }; let desc_str = match String::from_utf8(description.slice().to_vec()) { Ok(val) => val, - Err(err) => return output.write_err(err.into()), + Err(err) => return write_err(output, err.into()), }; if let Err(err) = target_cache_set(name, desc_str, native) { - return output.write_err(err); + return write_err(output, err); }; UserOutcomeKind::Success @@ -298,8 +264,8 @@ pub unsafe extern "C" fn stylus_call( }; let status = match instance.run_main(&calldata, config, ink) { - Err(e) | Ok(UserOutcome::Failure(e)) => output.write_err(e.wrap_err("call failed")), - Ok(outcome) => output.write_outcome(outcome), + Err(e) | Ok(UserOutcome::Failure(e)) => write_err(output, e.wrap_err("call failed")), + Ok(outcome) => write_outcome(output, outcome), }; let ink_left = match status { UserOutcomeKind::OutOfStack => Ink(0), // take all gas when out of stack @@ -352,18 +318,6 @@ pub extern "C" fn stylus_reorg_vm(_block: u64, arbos_tag: u32) { InitCache::clear_long_term(arbos_tag); } -/// Frees the vector. Does nothing when the vector is null. -/// -/// # Safety -/// -/// Must only be called once per vec. -#[no_mangle] -pub unsafe extern "C" fn stylus_drop_vec(vec: RustBytes) { - if !vec.ptr.is_null() { - mem::drop(vec.into_vec()) - } -} - /// Gets cache metrics. /// /// # Safety diff --git a/arbos/programs/native.go b/arbos/programs/native.go index f162704995..73d3fe83d7 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -464,7 +464,7 @@ func (vec *rustBytes) intoBytes() []byte { } func (vec *rustBytes) drop() { - C.stylus_drop_vec(*vec) + C.free_rust_bytes(*vec) } func goSlice(slice []byte) C.GoSliceData { diff --git a/validator/server_arb/machine.go b/validator/server_arb/machine.go index 09a00635fb..c781234124 100644 --- a/validator/server_arb/machine.go +++ b/validator/server_arb/machine.go @@ -304,9 +304,10 @@ func (m *ArbitratorMachine) ProveNextStep() []byte { m.mutex.Lock() defer m.mutex.Unlock() - rustProof := C.arbitrator_gen_proof(m.ptr) - proofBytes := C.GoBytes(unsafe.Pointer(rustProof.ptr), C.int(rustProof.len)) - C.arbitrator_free_proof(rustProof) + output := &C.RustBytes{} + C.arbitrator_gen_proof(m.ptr, output) + proofBytes := C.GoBytes(unsafe.Pointer(output.ptr), C.int(output.len)) + C.free_rust_bytes(*output) return proofBytes } From 6928d0b4f63561ea5441fd45a47e40596e8943e0 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Thu, 12 Dec 2024 11:57:05 -0300 Subject: [PATCH 21/25] Remove repeated code in encodeAddBatch function --- arbnode/batch_poster.go | 54 +++++++++-------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 1ffe9e3540..a667abd08f 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -984,57 +984,27 @@ func (b *BatchPoster) encodeAddBatch( if !ok { return nil, nil, errors.New("failed to find add batch method") } - - var calldata []byte + var args []any var kzgBlobs []kzg4844.Blob var err error + args = append(args, seqNum) if use4844 { kzgBlobs, err = blobs.EncodeBlobs(l2MessageData) if err != nil { return nil, nil, fmt.Errorf("failed to encode blobs: %w", err) } - } - switch methodName { - case sequencerBatchPostWithBlobsMethodName: + } else { // EIP4844 transactions to the sequencer inbox will not use transaction calldata for L2 info. - calldata, err = method.Inputs.Pack( - seqNum, - new(big.Int).SetUint64(delayedMsg), - b.config().gasRefunder, - new(big.Int).SetUint64(uint64(prevMsgNum)), - new(big.Int).SetUint64(uint64(newMsgNum)), - ) - case sequencerBatchPostWithBlobsDelayProofMethodName: - calldata, err = method.Inputs.Pack( - seqNum, - new(big.Int).SetUint64(delayedMsg), - b.config().gasRefunder, - new(big.Int).SetUint64(uint64(prevMsgNum)), - new(big.Int).SetUint64(uint64(newMsgNum)), - delayProof, - ) - case sequencerBatchPostMethodName: - calldata, err = method.Inputs.Pack( - seqNum, - l2MessageData, - new(big.Int).SetUint64(delayedMsg), - b.config().gasRefunder, - new(big.Int).SetUint64(uint64(prevMsgNum)), - new(big.Int).SetUint64(uint64(newMsgNum)), - ) - case sequencerBatchPostDelayProofMethodName: - calldata, err = method.Inputs.Pack( - seqNum, - l2MessageData, - new(big.Int).SetUint64(delayedMsg), - b.config().gasRefunder, - new(big.Int).SetUint64(uint64(prevMsgNum)), - new(big.Int).SetUint64(uint64(newMsgNum)), - delayProof, - ) - default: - panic("impossible") + args = append(args, l2MessageData) + } + args = append(args, new(big.Int).SetUint64(delayedMsg)) + args = append(args, b.config().gasRefunder) + args = append(args, new(big.Int).SetUint64(uint64(prevMsgNum))) + args = append(args, new(big.Int).SetUint64(uint64(newMsgNum))) + if delayProof != nil { + args = append(args, delayProof) } + calldata, err := method.Inputs.Pack(args...) if err != nil { return nil, nil, err } From 708cc0c217f9cc953b267e72a2560102d4821280 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Thu, 12 Dec 2024 12:20:23 -0300 Subject: [PATCH 22/25] Add margin to delay buffer threshold This ensures the delay buffer won't be slowly consumed if the threshold is constantly being reached. --- arbnode/batch_poster.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index a667abd08f..45bd70c92b 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -174,6 +174,7 @@ type BatchPosterConfig struct { ReorgResistanceMargin time.Duration `koanf:"reorg-resistance-margin" reload:"hot"` CheckBatchCorrectness bool `koanf:"check-batch-correctness"` MaxEmptyBatchDelay time.Duration `koanf:"max-empty-batch-delay"` + DelayBufferThresholdMargin uint64 `koanf:"delay-buffer-threshold-margin"` gasRefunder common.Address l1BlockBound l1BlockBound @@ -232,6 +233,7 @@ func BatchPosterConfigAddOptions(prefix string, f *pflag.FlagSet) { f.Duration(prefix+".reorg-resistance-margin", DefaultBatchPosterConfig.ReorgResistanceMargin, "do not post batch if its within this duration from layer 1 minimum bounds. Requires l1-block-bound option not be set to \"ignore\"") f.Bool(prefix+".check-batch-correctness", DefaultBatchPosterConfig.CheckBatchCorrectness, "setting this to true will run the batch against an inbox multiplexer and verifies that it produces the correct set of messages") f.Duration(prefix+".max-empty-batch-delay", DefaultBatchPosterConfig.MaxEmptyBatchDelay, "maximum empty batch posting delay, batch poster will only be able to post an empty batch if this time period building a batch has passed") + f.Uint64(prefix+".delay-buffer-threshold-margin", DefaultBatchPosterConfig.DelayBufferThresholdMargin, "the number of blocks to post the batch before reaching the delay buffer threshold") redislock.AddConfigOptions(prefix+".redis-lock", f) dataposter.DataPosterConfigAddOptions(prefix+".data-poster", f, dataposter.DefaultDataPosterConfig) genericconf.WalletConfigAddOptions(prefix+".parent-chain-wallet", f, DefaultBatchPosterConfig.ParentChainWallet.Pathname) @@ -265,6 +267,7 @@ var DefaultBatchPosterConfig = BatchPosterConfig{ ReorgResistanceMargin: 10 * time.Minute, CheckBatchCorrectness: true, MaxEmptyBatchDelay: 3 * 24 * time.Hour, + DelayBufferThresholdMargin: 25, // 5 minutes considering 12-second blocks } var DefaultBatchPosterL1WalletConfig = genericconf.WalletConfig{ @@ -296,6 +299,7 @@ var TestBatchPosterConfig = BatchPosterConfig{ UseAccessLists: true, GasEstimateBaseFeeMultipleBips: arbmath.OneInUBips * 3 / 2, CheckBatchCorrectness: true, + DelayBufferThresholdMargin: 0, } type BatchPosterOpts struct { @@ -1366,7 +1370,8 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) } latestBlock := latestHeader.Number.Uint64() firstDelayedMsgBlock := b.building.firstDelayedMsg.Message.Header.BlockNumber - if latestBlock >= firstDelayedMsgBlock+delayBuffer.Threshold { + threasholdLimit := firstDelayedMsgBlock + delayBuffer.Threshold - b.config().DelayBufferThresholdMargin + if latestBlock >= threasholdLimit { log.Info("force post batch because of the delay buffer", "firstDelayedMsgBlock", firstDelayedMsgBlock, "threshold", delayBuffer.Threshold, From 07d1da35e45d3dd1d9d2e3eae7fedb69c9e494a3 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Thu, 12 Dec 2024 13:03:47 -0300 Subject: [PATCH 23/25] Set ensure-rollup-deployment to false in testnode --- nitro-testnode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nitro-testnode b/nitro-testnode index fa19e22104..c177f28234 160000 --- a/nitro-testnode +++ b/nitro-testnode @@ -1 +1 @@ -Subproject commit fa19e2210403ad24519ea46c2d337f54a9f47593 +Subproject commit c177f282340285bcdae2d6a784547e2bb8b97498 From e2c4dc22ab550dc4728f22ca10e8b4c8a67e04f9 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 12 Dec 2024 09:09:35 -0700 Subject: [PATCH 24/25] Don't allocate for zero length bytes --- arbos/programs/native.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 73d3fe83d7..cfc1170c5b 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -450,10 +450,16 @@ func addressToBytes20(addr common.Address) bytes20 { } func (slice *rustSlice) read() []byte { + if slice.len == 0 { + return nil + } return arbutil.PointerToSlice((*byte)(slice.ptr), int(slice.len)) } func (vec *rustBytes) read() []byte { + if vec.len == 0 { + return nil + } return arbutil.PointerToSlice((*byte)(vec.ptr), int(vec.len)) } From be3c62209592511b67e5b78d743102d6315ded8e Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 12 Dec 2024 10:10:28 -0700 Subject: [PATCH 25/25] Also avoid allocating zero len slice in ProveNextStep --- validator/server_arb/machine.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validator/server_arb/machine.go b/validator/server_arb/machine.go index c781234124..e4e07d3c2d 100644 --- a/validator/server_arb/machine.go +++ b/validator/server_arb/machine.go @@ -306,8 +306,11 @@ func (m *ArbitratorMachine) ProveNextStep() []byte { output := &C.RustBytes{} C.arbitrator_gen_proof(m.ptr, output) + defer C.free_rust_bytes(*output) + if output.len == 0 { + return nil + } proofBytes := C.GoBytes(unsafe.Pointer(output.ptr), C.int(output.len)) - C.free_rust_bytes(*output) return proofBytes }