From 6228940f9cb3473d084071ab9505a6275e0525bb Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Fri, 15 Sep 2023 13:18:38 -0500 Subject: [PATCH 1/8] add methods to configure brotli compression level in ArbOS 12 --- arbcompress/compress_common.go | 5 ++- arbcompress/compress_test.go | 2 +- arbitrator/prover/test-cases/go/main.go | 3 +- arbos/arbosState/arbosstate.go | 3 ++ arbos/l1pricing/l1pricing.go | 41 +++++++++++++++++++------ contracts | 2 +- precompiles/ArbOwner.go | 4 +++ precompiles/ArbOwnerPublic.go | 5 +++ precompiles/precompile.go | 2 ++ system_tests/fees_test.go | 2 +- system_tests/state_fuzz_test.go | 3 +- 11 files changed, 55 insertions(+), 17 deletions(-) diff --git a/arbcompress/compress_common.go b/arbcompress/compress_common.go index 6b66fe302b..7d3976d562 100644 --- a/arbcompress/compress_common.go +++ b/arbcompress/compress_common.go @@ -3,7 +3,6 @@ package arbcompress -const LEVEL_FAST = 0 const LEVEL_WELL = 11 const WINDOW_SIZE = 22 // BROTLI_DEFAULT_WINDOW @@ -11,6 +10,6 @@ func compressedBufferSizeFor(length int) int { return length + (length>>10)*8 + 64 // actual limit is: length + (length >> 14) * 4 + 6 } -func CompressFast(input []byte) ([]byte, error) { - return compressLevel(input, LEVEL_FAST) +func CompressFast(input []byte, level int) ([]byte, error) { + return compressLevel(input, level) } diff --git a/arbcompress/compress_test.go b/arbcompress/compress_test.go index fffcda8923..88e7eb4eb5 100644 --- a/arbcompress/compress_test.go +++ b/arbcompress/compress_test.go @@ -27,7 +27,7 @@ func testCompressDecompress(t *testing.T, data []byte) { } testDecompress(t, compressedWell, data) - compressedFast, err := CompressFast(data) + compressedFast, err := CompressFast(data, 0) if err != nil { t.Fatal(err) } diff --git a/arbitrator/prover/test-cases/go/main.go b/arbitrator/prover/test-cases/go/main.go index a5a1028fb0..8df8b22556 100644 --- a/arbitrator/prover/test-cases/go/main.go +++ b/arbitrator/prover/test-cases/go/main.go @@ -13,6 +13,7 @@ import ( merkletree "github.com/wealdtech/go-merkletree" "github.com/offchainlabs/nitro/arbcompress" + "github.com/offchainlabs/nitro/arbos/l1pricing" ) // MerkleSample is an example using the Merkle tree to generate and verify proofs. @@ -42,7 +43,7 @@ func MerkleSample(data [][]byte, toproove int) (bool, error) { } func testCompression(data []byte) { - compressed, err := arbcompress.CompressFast(data) + compressed, err := arbcompress.CompressFast(data, l1pricing.InitialBrotliCompressionLevel) if err != nil { panic(err) } diff --git a/arbos/arbosState/arbosstate.go b/arbos/arbosState/arbosstate.go index 48e29e1219..0be5e51f8b 100644 --- a/arbos/arbosState/arbosstate.go +++ b/arbos/arbosState/arbosstate.go @@ -318,6 +318,9 @@ func (state *ArbosState) UpgradeArbosVersion( if !firstTime { ensure(state.chainOwners.ClearList()) } + case 11: + // Update Brotli compression level for fast compression from 0 to 1 + ensure(state.l1PricingState.SetBrotliCompressionLevel(1)) default: return fmt.Errorf( "the chain is upgrading to unsupported ArbOS version %v, %w", diff --git a/arbos/l1pricing/l1pricing.go b/arbos/l1pricing/l1pricing.go index 34d6021f00..6f90a9e3b7 100644 --- a/arbos/l1pricing/l1pricing.go +++ b/arbos/l1pricing/l1pricing.go @@ -36,8 +36,9 @@ type L1PricingState struct { inertia storage.StorageBackedUint64 perUnitReward storage.StorageBackedUint64 // variables - lastUpdateTime storage.StorageBackedUint64 // timestamp of the last update from L1 that we processed - fundsDueForRewards storage.StorageBackedBigInt + lastUpdateTime storage.StorageBackedUint64 // timestamp of the last update from L1 that we processed + fundsDueForRewards storage.StorageBackedBigInt + brotliCompressionLevel storage.StorageBackedUint64 // brotli compression level used for pricing // funds collected since update are recorded as the balance in account L1PricerFundsPoolAddress unitsSinceUpdate storage.StorageBackedUint64 // calldata units collected for since last update pricePerUnit storage.StorageBackedBigUint // current price per calldata unit @@ -63,6 +64,7 @@ const ( perUnitRewardOffset lastUpdateTimeOffset fundsDueForRewardsOffset + brotliCompressionLevelOffset unitsSinceOffset pricePerUnitOffset lastSurplusOffset @@ -72,10 +74,11 @@ const ( ) const ( - InitialInertia = 10 - InitialPerUnitReward = 10 - InitialPerBatchGasCostV6 = 100_000 - InitialPerBatchGasCostV12 = 210_000 // overriden as part of the upgrade + InitialInertia = 10 + InitialPerUnitReward = 10 + InitialPerBatchGasCostV6 = 100_000 + InitialPerBatchGasCostV12 = 210_000 // overriden as part of the upgrade + InitialBrotliCompressionLevel = 0 ) // one minute at 100000 bytes / sec @@ -112,6 +115,10 @@ func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient comm if err := pricePerUnit.SetSaturatingWithWarning(initialL1BaseFee, "initial L1 base fee (storing in price per unit)"); err != nil { return err } + brotliCompressionLevel := sto.OpenStorageBackedInt64(brotliCompressionLevelOffset) + if err := brotliCompressionLevel.Set(InitialBrotliCompressionLevel); err != nil { + return err + } return nil } @@ -125,6 +132,7 @@ func OpenL1PricingState(sto *storage.Storage) *L1PricingState { sto.OpenStorageBackedUint64(perUnitRewardOffset), sto.OpenStorageBackedUint64(lastUpdateTimeOffset), sto.OpenStorageBackedBigInt(fundsDueForRewardsOffset), + sto.OpenStorageBackedUint64(brotliCompressionLevelOffset), sto.OpenStorageBackedUint64(unitsSinceOffset), sto.OpenStorageBackedBigUint(pricePerUnitOffset), sto.OpenStorageBackedBigInt(lastSurplusOffset), @@ -254,6 +262,17 @@ func (ps *L1PricingState) SetL1FeesAvailable(val *big.Int) error { return ps.l1FeesAvailable.SetChecked(val) } +func (ps *L1PricingState) BrotliCompressionLevel() (uint64, error) { + return ps.brotliCompressionLevel.Get() +} + +func (ps *L1PricingState) SetBrotliCompressionLevel(val uint64) error { + if val <= arbcompress.LEVEL_WELL { + return ps.brotliCompressionLevel.Set(val) + } + return errors.New("invalid brotli compression level") +} + func (ps *L1PricingState) AddToL1FeesAvailable(delta *big.Int) (*big.Int, error) { old, err := ps.L1FeesAvailable() if err != nil { @@ -500,7 +519,11 @@ func (ps *L1PricingState) getPosterUnitsWithoutCache(tx *types.Transaction, post return 0 } - l1Bytes, err := byteCountAfterBrotli0(txBytes) + level, err := ps.BrotliCompressionLevel() + if err != nil { + panic(fmt.Sprintf("failed to get brotli compression level: %v", err)) + } + l1Bytes, err := byteCountAfterBrotliLevel(txBytes, int(level)) if err != nil { panic(fmt.Sprintf("failed to compress tx: %v", err)) } @@ -585,8 +608,8 @@ func (ps *L1PricingState) PosterDataCost(message *core.Message, poster common.Ad return am.BigMulByUint(pricePerUnit, units), units } -func byteCountAfterBrotli0(input []byte) (uint64, error) { - compressed, err := arbcompress.CompressFast(input) +func byteCountAfterBrotliLevel(input []byte, level int) (uint64, error) { + compressed, err := arbcompress.CompressFast(input, level) if err != nil { return 0, err } diff --git a/contracts b/contracts index 97cfbe00ff..55d096e219 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 97cfbe00ff0eea4d7f5f5f3afb01598c19ddabc4 +Subproject commit 55d096e219f352344bb7ba87ad66228f708d0a7a diff --git a/precompiles/ArbOwner.go b/precompiles/ArbOwner.go index 1abf1d0d09..2384bfbd8c 100644 --- a/precompiles/ArbOwner.go +++ b/precompiles/ArbOwner.go @@ -142,6 +142,10 @@ func (con ArbOwner) SetAmortizedCostCapBips(c ctx, evm mech, cap uint64) error { return c.State.L1PricingState().SetAmortizedCostCapBips(cap) } +func (con ArbOwner) SetBrotliCompressionLevel(c ctx, evm mech, level uint64) error { + return c.State.L1PricingState().SetBrotliCompressionLevel(level) +} + func (con ArbOwner) ReleaseL1PricerSurplusFunds(c ctx, evm mech, maxWeiToRelease huge) (huge, error) { balance := evm.StateDB.GetBalance(l1pricing.L1PricerFundsPoolAddress) l1p := c.State.L1PricingState() diff --git a/precompiles/ArbOwnerPublic.go b/precompiles/ArbOwnerPublic.go index fb4326b1ce..3952f221de 100644 --- a/precompiles/ArbOwnerPublic.go +++ b/precompiles/ArbOwnerPublic.go @@ -47,3 +47,8 @@ func (con ArbOwnerPublic) GetInfraFeeAccount(c ctx, evm mech) (addr, error) { } return c.State.InfraFeeAccount() } + +// GetBrotliCompressionLevel gets the current brotli compression level used for fast compression +func (con ArbOwnerPublic) GetBrotliCompressionLevel(c ctx, evm mech) (uint64, error) { + return c.State.L1PricingState().BrotliCompressionLevel() +} diff --git a/precompiles/precompile.go b/precompiles/precompile.go index a91756e639..77102a95b9 100644 --- a/precompiles/precompile.go +++ b/precompiles/precompile.go @@ -554,6 +554,7 @@ func Precompiles() map[addr]ArbosPrecompile { ArbOwnerPublic := insert(MakePrecompile(templates.ArbOwnerPublicMetaData, &ArbOwnerPublic{Address: hex("6b")})) ArbOwnerPublic.methodsByName["GetInfraFeeAccount"].arbosVersion = 5 ArbOwnerPublic.methodsByName["RectifyChainOwner"].arbosVersion = 11 + ArbOwnerPublic.methodsByName["GetBrotliCompressionLevel"].arbosVersion = 12 ArbRetryableImpl := &ArbRetryableTx{Address: types.ArbRetryableTxAddress} ArbRetryable := insert(MakePrecompile(templates.ArbRetryableTxMetaData, ArbRetryableImpl)) @@ -589,6 +590,7 @@ func Precompiles() map[addr]ArbosPrecompile { ArbOwner.methodsByName["SetInfraFeeAccount"].arbosVersion = 5 ArbOwner.methodsByName["ReleaseL1PricerSurplusFunds"].arbosVersion = 10 ArbOwner.methodsByName["SetChainConfig"].arbosVersion = 11 + ArbOwner.methodsByName["SetBrotliCompressionLevel"].arbosVersion = 12 insert(ownerOnly(ArbOwnerImpl.Address, ArbOwner, emitOwnerActs)) insert(debugOnly(MakePrecompile(templates.ArbDebugMetaData, &ArbDebug{Address: hex("ff")}))) diff --git a/system_tests/fees_test.go b/system_tests/fees_test.go index bdd998357e..21e326e65f 100644 --- a/system_tests/fees_test.go +++ b/system_tests/fees_test.go @@ -303,7 +303,7 @@ func TestSequencerPriceAdjustsFrom25Gwei(t *testing.T) { func compressedTxSize(t *testing.T, tx *types.Transaction) uint64 { txBin, err := tx.MarshalBinary() Require(t, err) - compressed, err := arbcompress.CompressFast(txBin) + compressed, err := arbcompress.CompressFast(txBin, l1pricing.InitialBrotliCompressionLevel) Require(t, err) return uint64(len(compressed)) } diff --git a/system_tests/state_fuzz_test.go b/system_tests/state_fuzz_test.go index a8209499df..17aad870d7 100644 --- a/system_tests/state_fuzz_test.go +++ b/system_tests/state_fuzz_test.go @@ -24,6 +24,7 @@ import ( "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/arbos/arbosState" "github.com/offchainlabs/nitro/arbos/arbostypes" + "github.com/offchainlabs/nitro/arbos/l1pricing" "github.com/offchainlabs/nitro/arbos/l2pricing" "github.com/offchainlabs/nitro/arbstate" "github.com/offchainlabs/nitro/statetransfer" @@ -174,7 +175,7 @@ func FuzzStateTransition(f *testing.F) { binary.BigEndian.PutUint64(seqBatch[32:40], uint64(len(delayedMessages))) if compressSeqMsg { seqBatch = append(seqBatch, arbstate.BrotliMessageHeaderByte) - seqMsgCompressed, err := arbcompress.CompressFast(seqMsg) + seqMsgCompressed, err := arbcompress.CompressFast(seqMsg, l1pricing.InitialBrotliCompressionLevel) if err != nil { panic(fmt.Sprintf("failed to compress sequencer message: %v", err)) } From bc52aad3a4486ead6c5db4e90d37789763764aef Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Fri, 15 Sep 2023 14:37:34 -0500 Subject: [PATCH 2/8] fix error --- arbos/l1pricing/l1pricing.go | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arbos/l1pricing/l1pricing.go b/arbos/l1pricing/l1pricing.go index 6f90a9e3b7..b9b9761b0b 100644 --- a/arbos/l1pricing/l1pricing.go +++ b/arbos/l1pricing/l1pricing.go @@ -115,7 +115,7 @@ func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient comm if err := pricePerUnit.SetSaturatingWithWarning(initialL1BaseFee, "initial L1 base fee (storing in price per unit)"); err != nil { return err } - brotliCompressionLevel := sto.OpenStorageBackedInt64(brotliCompressionLevelOffset) + brotliCompressionLevel := sto.OpenStorageBackedUint64(brotliCompressionLevelOffset) if err := brotliCompressionLevel.Set(InitialBrotliCompressionLevel); err != nil { return err } diff --git a/contracts b/contracts index 55d096e219..bb2ca53132 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 55d096e219f352344bb7ba87ad66228f708d0a7a +Subproject commit bb2ca53132116a59386b5f5010e711f485162c13 From 321502016fd1b28a5f8948b80df9024ed80ae56f Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Mon, 18 Sep 2023 10:34:19 -0500 Subject: [PATCH 3/8] fix failing test --- Makefile | 2 +- arbos/arbosState/arbosstate.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 56bf4df3c6..ca299df2e6 100644 --- a/Makefile +++ b/Makefile @@ -212,7 +212,7 @@ $(arbitrator_jit): $(DEP_PREDICATE) .make/cbrotli-lib $(jit_files) $(arbitrator_cases)/rust/target/wasm32-wasi/release/%.wasm: $(arbitrator_cases)/rust/src/bin/%.rs $(arbitrator_cases)/rust/src/lib.rs cargo build --manifest-path $(arbitrator_cases)/rust/Cargo.toml --release --target wasm32-wasi --bin $(patsubst $(arbitrator_cases)/rust/target/wasm32-wasi/release/%.wasm,%, $@) -$(arbitrator_cases)/go/main: $(arbitrator_cases)/go/main.go +$(arbitrator_cases)/go/main: $(arbitrator_cases)/go/main.go .make/solgen cd $(arbitrator_cases)/go && GOOS=js GOARCH=wasm go build main.go $(arbitrator_generated_header): $(DEP_PREDICATE) arbitrator/prover/src/lib.rs arbitrator/prover/src/utils.rs diff --git a/arbos/arbosState/arbosstate.go b/arbos/arbosState/arbosstate.go index 0be5e51f8b..c87d0f224d 100644 --- a/arbos/arbosState/arbosstate.go +++ b/arbos/arbosState/arbosstate.go @@ -319,6 +319,14 @@ func (state *ArbosState) UpgradeArbosVersion( ensure(state.chainOwners.ClearList()) } case 11: + if !chainConfig.DebugMode() { + // This upgrade isn't finalized so we only want to support it for testing + return fmt.Errorf( + "the chain is upgrading to unsupported ArbOS version %v, %w", + state.arbosVersion+1, + ErrFatalNodeOutOfDate, + ) + } // Update Brotli compression level for fast compression from 0 to 1 ensure(state.l1PricingState.SetBrotliCompressionLevel(1)) default: From 91ff77fef2523cc6344b321d3b96eec76636e5fa Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Tue, 26 Sep 2023 16:46:01 -0500 Subject: [PATCH 4/8] update contracts pin --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index bb2ca53132..225b504e6d 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit bb2ca53132116a59386b5f5010e711f485162c13 +Subproject commit 225b504e6d801b15dcba93099339e6e74897714e From 291f88942c8cf4f22bc093ca11b515224060e2b3 Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Thu, 28 Sep 2023 10:08:07 -0500 Subject: [PATCH 5/8] address PR comments --- arbcompress/compress_common.go | 2 +- arbcompress/compress_test.go | 2 +- arbitrator/prover/test-cases/go/main.go | 3 +- arbnode/execution/tx_pre_checker.go | 6 ++- arbos/arbosState/arbosstate.go | 52 ++++++++++++++++--------- arbos/block_processor.go | 6 ++- arbos/l1pricing/l1pricing.go | 51 +++++++----------------- arbos/tx_processor.go | 6 ++- nodeInterface/NodeInterface.go | 12 +++++- nodeInterface/virtual-contracts.go | 7 +++- precompiles/ArbOwner.go | 2 +- precompiles/ArbOwnerPublic.go | 2 +- system_tests/fees_test.go | 2 +- system_tests/state_fuzz_test.go | 3 +- 14 files changed, 86 insertions(+), 70 deletions(-) diff --git a/arbcompress/compress_common.go b/arbcompress/compress_common.go index 7d3976d562..990fd2e2be 100644 --- a/arbcompress/compress_common.go +++ b/arbcompress/compress_common.go @@ -10,6 +10,6 @@ func compressedBufferSizeFor(length int) int { return length + (length>>10)*8 + 64 // actual limit is: length + (length >> 14) * 4 + 6 } -func CompressFast(input []byte, level int) ([]byte, error) { +func CompressLevel(input []byte, level int) ([]byte, error) { return compressLevel(input, level) } diff --git a/arbcompress/compress_test.go b/arbcompress/compress_test.go index 88e7eb4eb5..21629d9663 100644 --- a/arbcompress/compress_test.go +++ b/arbcompress/compress_test.go @@ -27,7 +27,7 @@ func testCompressDecompress(t *testing.T, data []byte) { } testDecompress(t, compressedWell, data) - compressedFast, err := CompressFast(data, 0) + compressedFast, err := CompressLevel(data, 0) if err != nil { t.Fatal(err) } diff --git a/arbitrator/prover/test-cases/go/main.go b/arbitrator/prover/test-cases/go/main.go index 8df8b22556..6efcf2c2db 100644 --- a/arbitrator/prover/test-cases/go/main.go +++ b/arbitrator/prover/test-cases/go/main.go @@ -13,7 +13,6 @@ import ( merkletree "github.com/wealdtech/go-merkletree" "github.com/offchainlabs/nitro/arbcompress" - "github.com/offchainlabs/nitro/arbos/l1pricing" ) // MerkleSample is an example using the Merkle tree to generate and verify proofs. @@ -43,7 +42,7 @@ func MerkleSample(data [][]byte, toproove int) (bool, error) { } func testCompression(data []byte) { - compressed, err := arbcompress.CompressFast(data, l1pricing.InitialBrotliCompressionLevel) + compressed, err := arbcompress.CompressLevel(data, 0) if err != nil { panic(err) } diff --git a/arbnode/execution/tx_pre_checker.go b/arbnode/execution/tx_pre_checker.go index 968a1f266b..12471ed19f 100644 --- a/arbnode/execution/tx_pre_checker.go +++ b/arbnode/execution/tx_pre_checker.go @@ -188,7 +188,11 @@ func PreCheckTx(bc *core.BlockChain, chainConfig *params.ChainConfig, header *ty if config.Strictness >= TxPreCheckerStrictnessFullValidation && tx.Nonce() > stateNonce { return MakeNonceError(sender, tx.Nonce(), stateNonce) } - dataCost, _ := arbos.L1PricingState().GetPosterInfo(tx, l1pricing.BatchPosterAddress) + brotliCompressionLevel, err := arbos.BrotliCompressionLevel() + if err != nil { + return fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + } + dataCost, _ := arbos.L1PricingState().GetPosterInfo(tx, l1pricing.BatchPosterAddress, brotliCompressionLevel) dataGas := arbmath.BigDiv(dataCost, header.BaseFee) if tx.Gas() < intrinsic+dataGas.Uint64() { return core.ErrIntrinsicGas diff --git a/arbos/arbosState/arbosstate.go b/arbos/arbosState/arbosstate.go index c87d0f224d..a47f4e790b 100644 --- a/arbos/arbosState/arbosstate.go +++ b/arbos/arbosState/arbosstate.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/offchainlabs/nitro/arbcompress" "github.com/offchainlabs/nitro/arbos/addressSet" "github.com/offchainlabs/nitro/arbos/addressTable" "github.com/offchainlabs/nitro/arbos/arbostypes" @@ -35,23 +36,24 @@ import ( // persisted beyond the end of the test.) type ArbosState struct { - arbosVersion uint64 // version of the ArbOS storage format and semantics - upgradeVersion storage.StorageBackedUint64 // version we're planning to upgrade to, or 0 if not planning to upgrade - upgradeTimestamp storage.StorageBackedUint64 // when to do the planned upgrade - networkFeeAccount storage.StorageBackedAddress - l1PricingState *l1pricing.L1PricingState - l2PricingState *l2pricing.L2PricingState - retryableState *retryables.RetryableState - addressTable *addressTable.AddressTable - chainOwners *addressSet.AddressSet - sendMerkle *merkleAccumulator.MerkleAccumulator - blockhashes *blockhash.Blockhashes - chainId storage.StorageBackedBigInt - chainConfig storage.StorageBackedBytes - genesisBlockNum storage.StorageBackedUint64 - infraFeeAccount storage.StorageBackedAddress - backingStorage *storage.Storage - Burner burn.Burner + arbosVersion uint64 // version of the ArbOS storage format and semantics + upgradeVersion storage.StorageBackedUint64 // version we're planning to upgrade to, or 0 if not planning to upgrade + upgradeTimestamp storage.StorageBackedUint64 // when to do the planned upgrade + networkFeeAccount storage.StorageBackedAddress + l1PricingState *l1pricing.L1PricingState + l2PricingState *l2pricing.L2PricingState + retryableState *retryables.RetryableState + addressTable *addressTable.AddressTable + chainOwners *addressSet.AddressSet + sendMerkle *merkleAccumulator.MerkleAccumulator + blockhashes *blockhash.Blockhashes + chainId storage.StorageBackedBigInt + chainConfig storage.StorageBackedBytes + genesisBlockNum storage.StorageBackedUint64 + infraFeeAccount storage.StorageBackedAddress + brotliCompressionLevel storage.StorageBackedUint64 // brotli compression level used for pricing + backingStorage *storage.Storage + Burner burn.Burner } var ErrUninitializedArbOS = errors.New("ArbOS uninitialized") @@ -82,6 +84,7 @@ func OpenArbosState(stateDB vm.StateDB, burner burn.Burner) (*ArbosState, error) backingStorage.OpenStorageBackedBytes(chainConfigSubspace), backingStorage.OpenStorageBackedUint64(uint64(genesisBlockNumOffset)), backingStorage.OpenStorageBackedAddress(uint64(infraFeeAccountOffset)), + backingStorage.OpenStorageBackedUint64(uint64(brotliCompressionLevelOffset)), backingStorage, burner, }, nil @@ -139,6 +142,7 @@ const ( chainIdOffset genesisBlockNumOffset infraFeeAccountOffset + brotliCompressionLevelOffset ) type SubspaceID []byte @@ -215,6 +219,7 @@ func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *p chainConfigStorage := sto.OpenStorageBackedBytes(chainConfigSubspace) _ = chainConfigStorage.Set(initMessage.SerializedChainConfig) _ = sto.SetUint64ByUint64(uint64(genesisBlockNumOffset), chainConfig.ArbitrumChainParams.GenesisBlockNum) + _ = sto.SetUint64ByUint64(uint64(brotliCompressionLevelOffset), 0) // default brotliCompressionLevel for fast compression is 0 initialRewardsRecipient := l1pricing.BatchPosterAddress if desiredArbosVersion >= 2 { @@ -328,7 +333,7 @@ func (state *ArbosState) UpgradeArbosVersion( ) } // Update Brotli compression level for fast compression from 0 to 1 - ensure(state.l1PricingState.SetBrotliCompressionLevel(1)) + ensure(state.SetBrotliCompressionLevel(1)) default: return fmt.Errorf( "the chain is upgrading to unsupported ArbOS version %v, %w", @@ -390,6 +395,17 @@ func (state *ArbosState) SetFormatVersion(val uint64) { state.Restrict(state.backingStorage.SetUint64ByUint64(uint64(versionOffset), val)) } +func (state *ArbosState) BrotliCompressionLevel() (uint64, error) { + return state.brotliCompressionLevel.Get() +} + +func (state *ArbosState) SetBrotliCompressionLevel(val uint64) error { + if val <= arbcompress.LEVEL_WELL { + return state.brotliCompressionLevel.Set(val) + } + return errors.New("invalid brotli compression level") +} + func (state *ArbosState) RetryableState() *retryables.RetryableState { return state.retryableState } diff --git a/arbos/block_processor.go b/arbos/block_processor.go index 87ecac9e77..3f7d357aff 100644 --- a/arbos/block_processor.go +++ b/arbos/block_processor.go @@ -271,7 +271,11 @@ func ProduceBlockAdvanced( if basefee.Sign() > 0 { dataGas = math.MaxUint64 - posterCost, _ := state.L1PricingState().GetPosterInfo(tx, poster) + brotliCompressionLevel, err := state.BrotliCompressionLevel() + if err != nil { + return nil, nil, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + } + posterCost, _ := state.L1PricingState().GetPosterInfo(tx, poster, brotliCompressionLevel) posterCostInL2Gas := arbmath.BigDiv(posterCost, basefee) if posterCostInL2Gas.IsUint64() { diff --git a/arbos/l1pricing/l1pricing.go b/arbos/l1pricing/l1pricing.go index b9b9761b0b..e506f76907 100644 --- a/arbos/l1pricing/l1pricing.go +++ b/arbos/l1pricing/l1pricing.go @@ -36,9 +36,8 @@ type L1PricingState struct { inertia storage.StorageBackedUint64 perUnitReward storage.StorageBackedUint64 // variables - lastUpdateTime storage.StorageBackedUint64 // timestamp of the last update from L1 that we processed - fundsDueForRewards storage.StorageBackedBigInt - brotliCompressionLevel storage.StorageBackedUint64 // brotli compression level used for pricing + lastUpdateTime storage.StorageBackedUint64 // timestamp of the last update from L1 that we processed + fundsDueForRewards storage.StorageBackedBigInt // funds collected since update are recorded as the balance in account L1PricerFundsPoolAddress unitsSinceUpdate storage.StorageBackedUint64 // calldata units collected for since last update pricePerUnit storage.StorageBackedBigUint // current price per calldata unit @@ -64,7 +63,6 @@ const ( perUnitRewardOffset lastUpdateTimeOffset fundsDueForRewardsOffset - brotliCompressionLevelOffset unitsSinceOffset pricePerUnitOffset lastSurplusOffset @@ -74,11 +72,10 @@ const ( ) const ( - InitialInertia = 10 - InitialPerUnitReward = 10 - InitialPerBatchGasCostV6 = 100_000 - InitialPerBatchGasCostV12 = 210_000 // overriden as part of the upgrade - InitialBrotliCompressionLevel = 0 + InitialInertia = 10 + InitialPerUnitReward = 10 + InitialPerBatchGasCostV6 = 100_000 + InitialPerBatchGasCostV12 = 210_000 // overriden as part of the upgrade ) // one minute at 100000 bytes / sec @@ -115,10 +112,6 @@ func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient comm if err := pricePerUnit.SetSaturatingWithWarning(initialL1BaseFee, "initial L1 base fee (storing in price per unit)"); err != nil { return err } - brotliCompressionLevel := sto.OpenStorageBackedUint64(brotliCompressionLevelOffset) - if err := brotliCompressionLevel.Set(InitialBrotliCompressionLevel); err != nil { - return err - } return nil } @@ -132,7 +125,6 @@ func OpenL1PricingState(sto *storage.Storage) *L1PricingState { sto.OpenStorageBackedUint64(perUnitRewardOffset), sto.OpenStorageBackedUint64(lastUpdateTimeOffset), sto.OpenStorageBackedBigInt(fundsDueForRewardsOffset), - sto.OpenStorageBackedUint64(brotliCompressionLevelOffset), sto.OpenStorageBackedUint64(unitsSinceOffset), sto.OpenStorageBackedBigUint(pricePerUnitOffset), sto.OpenStorageBackedBigInt(lastSurplusOffset), @@ -262,17 +254,6 @@ func (ps *L1PricingState) SetL1FeesAvailable(val *big.Int) error { return ps.l1FeesAvailable.SetChecked(val) } -func (ps *L1PricingState) BrotliCompressionLevel() (uint64, error) { - return ps.brotliCompressionLevel.Get() -} - -func (ps *L1PricingState) SetBrotliCompressionLevel(val uint64) error { - if val <= arbcompress.LEVEL_WELL { - return ps.brotliCompressionLevel.Set(val) - } - return errors.New("invalid brotli compression level") -} - func (ps *L1PricingState) AddToL1FeesAvailable(delta *big.Int) (*big.Int, error) { old, err := ps.L1FeesAvailable() if err != nil { @@ -508,7 +489,7 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending( return nil } -func (ps *L1PricingState) getPosterUnitsWithoutCache(tx *types.Transaction, posterAddr common.Address) uint64 { +func (ps *L1PricingState) getPosterUnitsWithoutCache(tx *types.Transaction, posterAddr common.Address, brotliCompressionLevel uint64) uint64 { if posterAddr != BatchPosterAddress { return 0 @@ -519,11 +500,7 @@ func (ps *L1PricingState) getPosterUnitsWithoutCache(tx *types.Transaction, post return 0 } - level, err := ps.BrotliCompressionLevel() - if err != nil { - panic(fmt.Sprintf("failed to get brotli compression level: %v", err)) - } - l1Bytes, err := byteCountAfterBrotliLevel(txBytes, int(level)) + l1Bytes, err := byteCountAfterBrotliLevel(txBytes, int(brotliCompressionLevel)) if err != nil { panic(fmt.Sprintf("failed to compress tx: %v", err)) } @@ -531,13 +508,13 @@ func (ps *L1PricingState) getPosterUnitsWithoutCache(tx *types.Transaction, post } // GetPosterInfo returns the poster cost and the calldata units for a transaction -func (ps *L1PricingState) GetPosterInfo(tx *types.Transaction, poster common.Address) (*big.Int, uint64) { +func (ps *L1PricingState) GetPosterInfo(tx *types.Transaction, poster common.Address, brotliCompressionLevel uint64) (*big.Int, uint64) { if poster != BatchPosterAddress { return common.Big0, 0 } units := atomic.LoadUint64(&tx.CalldataUnits) if units == 0 { - units = ps.getPosterUnitsWithoutCache(tx, poster) + units = ps.getPosterUnitsWithoutCache(tx, poster, brotliCompressionLevel) atomic.StoreUint64(&tx.CalldataUnits, units) } @@ -593,23 +570,23 @@ func makeFakeTxForMessage(message *core.Message) *types.Transaction { }) } -func (ps *L1PricingState) PosterDataCost(message *core.Message, poster common.Address) (*big.Int, uint64) { +func (ps *L1PricingState) PosterDataCost(message *core.Message, poster common.Address, brotliCompressionLevel uint64) (*big.Int, uint64) { tx := message.Tx if tx != nil { - return ps.GetPosterInfo(tx, poster) + return ps.GetPosterInfo(tx, poster, brotliCompressionLevel) } // Otherwise, we don't have an underlying transaction, so we're likely in gas estimation. // We'll instead make a fake tx from the message info we do have, and then pad our cost a bit to be safe. tx = makeFakeTxForMessage(message) - units := ps.getPosterUnitsWithoutCache(tx, poster) + units := ps.getPosterUnitsWithoutCache(tx, poster, brotliCompressionLevel) units = arbmath.UintMulByBips(units+estimationPaddingUnits, arbmath.OneInBips+estimationPaddingBasisPoints) pricePerUnit, _ := ps.PricePerUnit() return am.BigMulByUint(pricePerUnit, units), units } func byteCountAfterBrotliLevel(input []byte, level int) (uint64, error) { - compressed, err := arbcompress.CompressFast(input, level) + compressed, err := arbcompress.CompressLevel(input, level) if err != nil { return 0, err } diff --git a/arbos/tx_processor.go b/arbos/tx_processor.go index 0d44ac548e..6ef994d657 100644 --- a/arbos/tx_processor.go +++ b/arbos/tx_processor.go @@ -410,7 +410,11 @@ func (p *TxProcessor) GasChargingHook(gasRemaining *uint64) (common.Address, err // Since tips go to the network, and not to the poster, we use the basefee. // Note, this only determines the amount of gas bought, not the price per gas. - posterCost, calldataUnits := p.state.L1PricingState().PosterDataCost(p.msg, poster) + brotliCompressionLevel, err := p.state.BrotliCompressionLevel() + if err != nil { + return common.Address{}, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + } + posterCost, calldataUnits := p.state.L1PricingState().PosterDataCost(p.msg, poster, brotliCompressionLevel) if calldataUnits > 0 { p.state.Restrict(p.state.L1PricingState().AddToUnitsSinceUpdate(calldataUnits)) } diff --git a/nodeInterface/NodeInterface.go b/nodeInterface/NodeInterface.go index f13f8ce6c0..8351e3192d 100644 --- a/nodeInterface/NodeInterface.go +++ b/nodeInterface/NodeInterface.go @@ -469,7 +469,11 @@ func (n NodeInterface) GasEstimateL1Component( // Compute the fee paid for L1 in L2 terms // See in GasChargingHook that this does not induce truncation error // - feeForL1, _ := pricing.PosterDataCost(msg, l1pricing.BatchPosterAddress) + brotliCompressionLevel, err := c.State.BrotliCompressionLevel() + if err != nil { + return 0, nil, nil, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + } + feeForL1, _ := pricing.PosterDataCost(msg, l1pricing.BatchPosterAddress, brotliCompressionLevel) feeForL1 = arbmath.BigMulByBips(feeForL1, arbos.GasEstimationL1PricePadding) gasForL1 := arbmath.BigDiv(feeForL1, baseFee).Uint64() return gasForL1, baseFee, l1BaseFeeEstimate, nil @@ -507,7 +511,11 @@ func (n NodeInterface) GasEstimateComponents( if err != nil { return 0, 0, nil, nil, err } - feeForL1, _ := pricing.PosterDataCost(msg, l1pricing.BatchPosterAddress) + brotliCompressionLevel, err := c.State.BrotliCompressionLevel() + if err != nil { + return 0, 0, nil, nil, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + } + feeForL1, _ := pricing.PosterDataCost(msg, l1pricing.BatchPosterAddress, brotliCompressionLevel) baseFee, err := c.State.L2PricingState().BaseFeeWei() if err != nil { diff --git a/nodeInterface/virtual-contracts.go b/nodeInterface/virtual-contracts.go index ee81c1c3e6..71c3275179 100644 --- a/nodeInterface/virtual-contracts.go +++ b/nodeInterface/virtual-contracts.go @@ -135,7 +135,12 @@ func init() { return } - posterCost, _ := state.L1PricingState().PosterDataCost(msg, l1pricing.BatchPosterAddress) + brotliCompressionLevel, err := state.BrotliCompressionLevel() + if err != nil { + log.Error("failed to get brotliCompressionLevel", "err", err) + return + } + posterCost, _ := state.L1PricingState().PosterDataCost(msg, l1pricing.BatchPosterAddress, brotliCompressionLevel) posterCostInL2Gas := arbos.GetPosterGas(state, header.BaseFee, msg.TxRunMode, posterCost) *gascap = arbmath.SaturatingUAdd(*gascap, posterCostInL2Gas) } diff --git a/precompiles/ArbOwner.go b/precompiles/ArbOwner.go index 2384bfbd8c..166768940b 100644 --- a/precompiles/ArbOwner.go +++ b/precompiles/ArbOwner.go @@ -143,7 +143,7 @@ func (con ArbOwner) SetAmortizedCostCapBips(c ctx, evm mech, cap uint64) error { } func (con ArbOwner) SetBrotliCompressionLevel(c ctx, evm mech, level uint64) error { - return c.State.L1PricingState().SetBrotliCompressionLevel(level) + return c.State.SetBrotliCompressionLevel(level) } func (con ArbOwner) ReleaseL1PricerSurplusFunds(c ctx, evm mech, maxWeiToRelease huge) (huge, error) { diff --git a/precompiles/ArbOwnerPublic.go b/precompiles/ArbOwnerPublic.go index 3952f221de..4064f41bef 100644 --- a/precompiles/ArbOwnerPublic.go +++ b/precompiles/ArbOwnerPublic.go @@ -50,5 +50,5 @@ func (con ArbOwnerPublic) GetInfraFeeAccount(c ctx, evm mech) (addr, error) { // GetBrotliCompressionLevel gets the current brotli compression level used for fast compression func (con ArbOwnerPublic) GetBrotliCompressionLevel(c ctx, evm mech) (uint64, error) { - return c.State.L1PricingState().BrotliCompressionLevel() + return c.State.BrotliCompressionLevel() } diff --git a/system_tests/fees_test.go b/system_tests/fees_test.go index 21e326e65f..ea7edc2ee8 100644 --- a/system_tests/fees_test.go +++ b/system_tests/fees_test.go @@ -303,7 +303,7 @@ func TestSequencerPriceAdjustsFrom25Gwei(t *testing.T) { func compressedTxSize(t *testing.T, tx *types.Transaction) uint64 { txBin, err := tx.MarshalBinary() Require(t, err) - compressed, err := arbcompress.CompressFast(txBin, l1pricing.InitialBrotliCompressionLevel) + compressed, err := arbcompress.CompressLevel(txBin, 0) Require(t, err) return uint64(len(compressed)) } diff --git a/system_tests/state_fuzz_test.go b/system_tests/state_fuzz_test.go index 17aad870d7..b14215fbf0 100644 --- a/system_tests/state_fuzz_test.go +++ b/system_tests/state_fuzz_test.go @@ -24,7 +24,6 @@ import ( "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/arbos/arbosState" "github.com/offchainlabs/nitro/arbos/arbostypes" - "github.com/offchainlabs/nitro/arbos/l1pricing" "github.com/offchainlabs/nitro/arbos/l2pricing" "github.com/offchainlabs/nitro/arbstate" "github.com/offchainlabs/nitro/statetransfer" @@ -175,7 +174,7 @@ func FuzzStateTransition(f *testing.F) { binary.BigEndian.PutUint64(seqBatch[32:40], uint64(len(delayedMessages))) if compressSeqMsg { seqBatch = append(seqBatch, arbstate.BrotliMessageHeaderByte) - seqMsgCompressed, err := arbcompress.CompressFast(seqMsg, l1pricing.InitialBrotliCompressionLevel) + seqMsgCompressed, err := arbcompress.CompressLevel(seqMsg, 0) if err != nil { panic(fmt.Sprintf("failed to compress sequencer message: %v", err)) } From 356564a8a0be04f40b9803ea7089a5f6952e106c Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Thu, 28 Sep 2023 10:21:37 -0500 Subject: [PATCH 6/8] update contracts pin --- Makefile | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ca299df2e6..56bf4df3c6 100644 --- a/Makefile +++ b/Makefile @@ -212,7 +212,7 @@ $(arbitrator_jit): $(DEP_PREDICATE) .make/cbrotli-lib $(jit_files) $(arbitrator_cases)/rust/target/wasm32-wasi/release/%.wasm: $(arbitrator_cases)/rust/src/bin/%.rs $(arbitrator_cases)/rust/src/lib.rs cargo build --manifest-path $(arbitrator_cases)/rust/Cargo.toml --release --target wasm32-wasi --bin $(patsubst $(arbitrator_cases)/rust/target/wasm32-wasi/release/%.wasm,%, $@) -$(arbitrator_cases)/go/main: $(arbitrator_cases)/go/main.go .make/solgen +$(arbitrator_cases)/go/main: $(arbitrator_cases)/go/main.go cd $(arbitrator_cases)/go && GOOS=js GOARCH=wasm go build main.go $(arbitrator_generated_header): $(DEP_PREDICATE) arbitrator/prover/src/lib.rs arbitrator/prover/src/utils.rs diff --git a/contracts b/contracts index 225b504e6d..41c4303a8e 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 225b504e6d801b15dcba93099339e6e74897714e +Subproject commit 41c4303a8e0a694da82a5ead0bcbf426c4f3cc6f From ed7c0fc8ba27c7d4922c1e37d119194a5176bc7a Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Thu, 28 Sep 2023 10:27:55 -0500 Subject: [PATCH 7/8] update contracts pin --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 41c4303a8e..ae11e7a864 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 41c4303a8e0a694da82a5ead0bcbf426c4f3cc6f +Subproject commit ae11e7a86488e28c706e062ae501bfb7157197c1 From 3234af9e88e4e360731b65b3269f5f5c2934d99d Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Thu, 28 Sep 2023 10:48:46 -0500 Subject: [PATCH 8/8] fix error message --- arbnode/execution/tx_pre_checker.go | 2 +- arbos/block_processor.go | 2 +- arbos/tx_processor.go | 2 +- nodeInterface/NodeInterface.go | 4 ++-- nodeInterface/virtual-contracts.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arbnode/execution/tx_pre_checker.go b/arbnode/execution/tx_pre_checker.go index 12471ed19f..7d9e26d16c 100644 --- a/arbnode/execution/tx_pre_checker.go +++ b/arbnode/execution/tx_pre_checker.go @@ -190,7 +190,7 @@ func PreCheckTx(bc *core.BlockChain, chainConfig *params.ChainConfig, header *ty } brotliCompressionLevel, err := arbos.BrotliCompressionLevel() if err != nil { - return fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + return fmt.Errorf("failed to get brotli compression level: %w", err) } dataCost, _ := arbos.L1PricingState().GetPosterInfo(tx, l1pricing.BatchPosterAddress, brotliCompressionLevel) dataGas := arbmath.BigDiv(dataCost, header.BaseFee) diff --git a/arbos/block_processor.go b/arbos/block_processor.go index 3f7d357aff..6f87864b61 100644 --- a/arbos/block_processor.go +++ b/arbos/block_processor.go @@ -273,7 +273,7 @@ func ProduceBlockAdvanced( dataGas = math.MaxUint64 brotliCompressionLevel, err := state.BrotliCompressionLevel() if err != nil { - return nil, nil, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + return nil, nil, fmt.Errorf("failed to get brotli compression level: %w", err) } posterCost, _ := state.L1PricingState().GetPosterInfo(tx, poster, brotliCompressionLevel) posterCostInL2Gas := arbmath.BigDiv(posterCost, basefee) diff --git a/arbos/tx_processor.go b/arbos/tx_processor.go index 6ef994d657..3572042a09 100644 --- a/arbos/tx_processor.go +++ b/arbos/tx_processor.go @@ -412,7 +412,7 @@ func (p *TxProcessor) GasChargingHook(gasRemaining *uint64) (common.Address, err brotliCompressionLevel, err := p.state.BrotliCompressionLevel() if err != nil { - return common.Address{}, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + return common.Address{}, fmt.Errorf("failed to get brotli compression level: %w", err) } posterCost, calldataUnits := p.state.L1PricingState().PosterDataCost(p.msg, poster, brotliCompressionLevel) if calldataUnits > 0 { diff --git a/nodeInterface/NodeInterface.go b/nodeInterface/NodeInterface.go index 8351e3192d..d795345839 100644 --- a/nodeInterface/NodeInterface.go +++ b/nodeInterface/NodeInterface.go @@ -471,7 +471,7 @@ func (n NodeInterface) GasEstimateL1Component( // brotliCompressionLevel, err := c.State.BrotliCompressionLevel() if err != nil { - return 0, nil, nil, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + return 0, nil, nil, fmt.Errorf("failed to get brotli compression level: %w", err) } feeForL1, _ := pricing.PosterDataCost(msg, l1pricing.BatchPosterAddress, brotliCompressionLevel) feeForL1 = arbmath.BigMulByBips(feeForL1, arbos.GasEstimationL1PricePadding) @@ -513,7 +513,7 @@ func (n NodeInterface) GasEstimateComponents( } brotliCompressionLevel, err := c.State.BrotliCompressionLevel() if err != nil { - return 0, 0, nil, nil, fmt.Errorf("failed to get brotliCompressionLevel: %w", err) + return 0, 0, nil, nil, fmt.Errorf("failed to get brotli compression level: %w", err) } feeForL1, _ := pricing.PosterDataCost(msg, l1pricing.BatchPosterAddress, brotliCompressionLevel) diff --git a/nodeInterface/virtual-contracts.go b/nodeInterface/virtual-contracts.go index 71c3275179..ec375699b7 100644 --- a/nodeInterface/virtual-contracts.go +++ b/nodeInterface/virtual-contracts.go @@ -137,7 +137,7 @@ func init() { brotliCompressionLevel, err := state.BrotliCompressionLevel() if err != nil { - log.Error("failed to get brotliCompressionLevel", "err", err) + log.Error("failed to get brotli compression level", "err", err) return } posterCost, _ := state.L1PricingState().PosterDataCost(msg, l1pricing.BatchPosterAddress, brotliCompressionLevel)