Skip to content

Commit

Permalink
Merge pull request #1704 from OffchainLabs/init-message-data-cost
Browse files Browse the repository at this point in the history
Parse the initial data cost out of the init message
  • Loading branch information
PlasmaPower authored Jun 20, 2023
2 parents 4ce531a + db7961d commit 152b9ff
Show file tree
Hide file tree
Showing 20 changed files with 155 additions and 99 deletions.
9 changes: 5 additions & 4 deletions arbnode/execution/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/offchainlabs/nitro/arbos"
"github.com/offchainlabs/nitro/arbos/arbosState"
"github.com/offchainlabs/nitro/arbos/arbostypes"
"github.com/offchainlabs/nitro/gethhook"
"github.com/offchainlabs/nitro/statetransfer"
)
Expand Down Expand Up @@ -82,7 +83,7 @@ func DefaultCacheConfigFor(stack *node.Node, cachingConfig *CachingConfig) *core
}
}

func WriteOrTestGenblock(chainDb ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, serializedChainConfig []byte, accountsPerSync uint) error {
func WriteOrTestGenblock(chainDb ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, accountsPerSync uint) error {
EmptyHash := common.Hash{}
prevHash := EmptyHash
prevDifficulty := big.NewInt(0)
Expand All @@ -103,7 +104,7 @@ func WriteOrTestGenblock(chainDb ethdb.Database, initData statetransfer.InitData
}
timestamp = prevHeader.Time
}
stateRoot, err := arbosState.InitializeArbosInDatabase(chainDb, initData, chainConfig, serializedChainConfig, timestamp, accountsPerSync)
stateRoot, err := arbosState.InitializeArbosInDatabase(chainDb, initData, chainConfig, initMessage, timestamp, accountsPerSync)
if err != nil {
return err
}
Expand Down Expand Up @@ -170,8 +171,8 @@ func GetBlockChain(chainDb ethdb.Database, cacheConfig *core.CacheConfig, chainC
return core.NewBlockChain(chainDb, cacheConfig, chainConfig, nil, nil, engine, vmConfig, shouldPreserveFalse, &txLookupLimit)
}

func WriteOrTestBlockChain(chainDb ethdb.Database, cacheConfig *core.CacheConfig, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, serializedChainConfig []byte, txLookupLimit uint64, accountsPerSync uint) (*core.BlockChain, error) {
err := WriteOrTestGenblock(chainDb, initData, chainConfig, serializedChainConfig, accountsPerSync)
func WriteOrTestBlockChain(chainDb ethdb.Database, cacheConfig *core.CacheConfig, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, txLookupLimit uint64, accountsPerSync uint) (*core.BlockChain, error) {
err := WriteOrTestGenblock(chainDb, initData, chainConfig, initMessage, accountsPerSync)
if err != nil {
return nil, err
}
Expand Down
10 changes: 5 additions & 5 deletions arbnode/inbox_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,17 @@ func (r *InboxReader) Start(ctxIn context.Context) error {
if err != nil {
return err
}
initChainId, initChainConfig, _, err := message.ParseInitMessage()
initMessage, err := message.ParseInitMessage()
if err != nil {
return err
}
chainConfig := r.tracker.txStreamer.chainConfig
configChainId := chainConfig.ChainID
if initChainId.Cmp(configChainId) != 0 {
return fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", configChainId, initChainId)
if initMessage.ChainId.Cmp(configChainId) != 0 {
return fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", configChainId, initMessage.ChainId)
}
if initChainConfig != nil {
if err := initChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil {
if initMessage.ChainConfig != nil {
if err := initMessage.ChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil {
return fmt.Errorf("incompatible chain config read from init message in L1 inbox: %w", err)
}
}
Expand Down
7 changes: 1 addition & 6 deletions arbnode/inbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package arbnode
import (
"context"
"encoding/binary"
"encoding/json"
"math/big"
"math/rand"
"testing"
Expand All @@ -33,10 +32,6 @@ import (

func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (*execution.ExecutionEngine, *TransactionStreamer, ethdb.Database, *core.BlockChain) {
chainConfig := params.ArbitrumDevTestChainConfig()
serializedChainConfig, err := json.Marshal(chainConfig)
if err != nil {
Fail(t, err)
}

initData := statetransfer.ArbosInitializationInfo{
Accounts: []statetransfer.AccountInitializationInfo{
Expand All @@ -51,7 +46,7 @@ func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (*
arbDb := rawdb.NewMemoryDatabase()
initReader := statetransfer.NewMemoryInitDataReader(&initData)

bc, err := execution.WriteOrTestBlockChain(chainDb, nil, initReader, chainConfig, serializedChainConfig, ConfigDefaultL2Test().TxLookupLimit, 0)
bc, err := execution.WriteOrTestBlockChain(chainDb, nil, initReader, chainConfig, arbostypes.TestInitMessage, ConfigDefaultL2Test().TxLookupLimit, 0)

if err != nil {
Fail(t, err)
Expand Down
14 changes: 5 additions & 9 deletions arbos/arbosState/arbosstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package arbosState

import (
"encoding/json"
"errors"
"fmt"
"math/big"
Expand All @@ -19,6 +18,7 @@ import (

"github.com/offchainlabs/nitro/arbos/addressSet"
"github.com/offchainlabs/nitro/arbos/addressTable"
"github.com/offchainlabs/nitro/arbos/arbostypes"
"github.com/offchainlabs/nitro/arbos/blockhash"
"github.com/offchainlabs/nitro/arbos/burn"
"github.com/offchainlabs/nitro/arbos/l1pricing"
Expand Down Expand Up @@ -112,11 +112,7 @@ func NewArbosMemoryBackedArbOSState() (*ArbosState, *state.StateDB) {
}
burner := burn.NewSystemBurner(nil, false)
chainConfig := params.ArbitrumDevTestChainConfig()
serializedChainConfig, err := json.Marshal(chainConfig)
if err != nil {
log.Crit("failed to serialize chain config", "error", err)
}
newState, err := InitializeArbosState(statedb, burner, chainConfig, serializedChainConfig)
newState, err := InitializeArbosState(statedb, burner, chainConfig, arbostypes.TestInitMessage)
if err != nil {
log.Crit("failed to open the ArbOS state", "error", err)
}
Expand Down Expand Up @@ -183,7 +179,7 @@ func getArbitrumOnlyGenesisPrecompiles(chainConfig *params.ChainConfig) []common
// start running long-lived chains, every change to the storage format will require defining a new version and
// providing upgrade code.

func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *params.ChainConfig, serializedChainConfig []byte) (*ArbosState, error) {
func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage) (*ArbosState, error) {
sto := storage.NewGeth(stateDB, burner)
arbosVersion, err := sto.GetUint64ByUint64(uint64(versionOffset))
if err != nil {
Expand Down Expand Up @@ -217,14 +213,14 @@ func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *p
}
_ = sto.SetByUint64(uint64(chainIdOffset), common.BigToHash(chainConfig.ChainID))
chainConfigStorage := sto.OpenStorageBackedBytes(chainConfigSubspace)
_ = chainConfigStorage.Set(serializedChainConfig)
_ = chainConfigStorage.Set(initMessage.SerializedChainConfig)
_ = sto.SetUint64ByUint64(uint64(genesisBlockNumOffset), chainConfig.ArbitrumChainParams.GenesisBlockNum)

initialRewardsRecipient := l1pricing.BatchPosterAddress
if desiredArbosVersion >= 2 {
initialRewardsRecipient = initialChainOwner
}
_ = l1pricing.InitializeL1PricingState(sto.OpenSubStorage(l1PricingSubspace), initialRewardsRecipient)
_ = l1pricing.InitializeL1PricingState(sto.OpenSubStorage(l1PricingSubspace), initialRewardsRecipient, initMessage.InitialL1BaseFee)
_ = l2pricing.InitializeL2PricingState(sto.OpenSubStorage(l2PricingSubspace))
_ = retryables.InitializeRetryableState(sto.OpenSubStorage(retryablesSubspace))
addressTable.Initialize(sto.OpenSubStorage(addressTableSubspace))
Expand Down
8 changes: 2 additions & 6 deletions arbos/arbosState/initialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/offchainlabs/nitro/arbos/arbostypes"
"github.com/offchainlabs/nitro/arbos/burn"
"github.com/offchainlabs/nitro/statetransfer"
"github.com/offchainlabs/nitro/util/testhelpers"
Expand Down Expand Up @@ -60,11 +60,7 @@ func tryMarshalUnmarshal(input *statetransfer.ArbosInitializationInfo, t *testin

initReader := statetransfer.NewMemoryInitDataReader(&initData)
chainConfig := params.ArbitrumDevTestChainConfig()
serializedChainConfig, err := json.Marshal(chainConfig)
if err != nil {
log.Crit("failed to serialize chain config", "error", err)
}
stateroot, err := InitializeArbosInDatabase(raw, initReader, chainConfig, serializedChainConfig, 0, 0)
stateroot, err := InitializeArbosInDatabase(raw, initReader, chainConfig, arbostypes.TestInitMessage, 0, 0)
Require(t, err)

stateDb, err := state.New(stateroot, state.NewDatabase(raw), nil)
Expand Down
5 changes: 3 additions & 2 deletions arbos/arbosState/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/offchainlabs/nitro/arbos/arbostypes"
"github.com/offchainlabs/nitro/arbos/burn"
"github.com/offchainlabs/nitro/arbos/l2pricing"
"github.com/offchainlabs/nitro/arbos/retryables"
Expand Down Expand Up @@ -49,7 +50,7 @@ func MakeGenesisBlock(parentHash common.Hash, blockNumber uint64, timestamp uint
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil))
}

func InitializeArbosInDatabase(db ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, serializedChainConfig []byte, timestamp uint64, accountsPerSync uint) (common.Hash, error) {
func InitializeArbosInDatabase(db ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, timestamp uint64, accountsPerSync uint) (common.Hash, error) {
stateDatabase := state.NewDatabase(db)
statedb, err := state.New(common.Hash{}, stateDatabase, nil)
if err != nil {
Expand All @@ -73,7 +74,7 @@ func InitializeArbosInDatabase(db ethdb.Database, initData statetransfer.InitDat
}

burner := burn.NewSystemBurner(nil, false)
arbosState, err := InitializeArbosState(statedb, burner, chainConfig, serializedChainConfig)
arbosState, err := InitializeArbosState(statedb, burner, chainConfig, initMessage)
if err != nil {
log.Crit("failed to open the ArbOS state", "error", err)
}
Expand Down
48 changes: 39 additions & 9 deletions arbos/arbostypes/incomingmessage.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,30 +234,60 @@ func ParseIncomingL1Message(rd io.Reader, batchFetcher FallibleBatchFetcher) (*L

type FallibleBatchFetcher func(batchNum uint64) ([]byte, error)

type ParsedInitMessage struct {
ChainId *big.Int
InitialL1BaseFee *big.Int

// These may be nil
ChainConfig *params.ChainConfig
SerializedChainConfig []byte
}

// The initial L1 pricing basefee starts at 50 GWei unless set in the init message
var DefaultInitialL1BaseFee = big.NewInt(50 * params.GWei)

var TestInitMessage = &ParsedInitMessage{
ChainId: params.ArbitrumDevTestChainConfig().ChainID,
InitialL1BaseFee: DefaultInitialL1BaseFee,
}

// ParseInitMessage returns the chain id on success
func (msg *L1IncomingMessage) ParseInitMessage() (*big.Int, *params.ChainConfig, []byte, error) {
func (msg *L1IncomingMessage) ParseInitMessage() (*ParsedInitMessage, error) {
if msg.Header.Kind != L1MessageType_Initialize {
return nil, nil, nil, fmt.Errorf("invalid init message kind %v", msg.Header.Kind)
return nil, fmt.Errorf("invalid init message kind %v", msg.Header.Kind)
}
basefee := new(big.Int).Set(DefaultInitialL1BaseFee)
var chainConfig params.ChainConfig
var chainId *big.Int
if len(msg.L2msg) == 32 {
chainId = new(big.Int).SetBytes(msg.L2msg[:32])
return chainId, nil, nil, nil
return &ParsedInitMessage{chainId, basefee, nil, nil}, nil
}
if len(msg.L2msg) > 32 {
chainId = new(big.Int).SetBytes(msg.L2msg[:32])
version := msg.L2msg[32]
if version == 0 && len(msg.L2msg) > 33 {
serializedChainConfig := msg.L2msg[33:]
err := json.Unmarshal(serializedChainConfig, &chainConfig)
reader := bytes.NewReader(msg.L2msg[33:])
switch version {
case 1:
var err error
basefee, err = util.Uint256FromReader(reader)
if err != nil {
return nil, err
}
fallthrough
case 0:
serializedChainConfig, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
err = json.Unmarshal(serializedChainConfig, &chainConfig)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to parse init message, err: %w, message data: %v", err, string(msg.L2msg))
return nil, fmt.Errorf("failed to parse init message, err: %w, message data: %v", err, string(msg.L2msg))
}
return chainId, &chainConfig, serializedChainConfig, nil
return &ParsedInitMessage{chainId, basefee, &chainConfig, serializedChainConfig}, nil
}
}
return nil, nil, nil, fmt.Errorf("invalid init message data %v", string(msg.L2msg))
return nil, fmt.Errorf("invalid init message data %v", string(msg.L2msg))
}

func ParseBatchPostingReportMessageFields(rd io.Reader) (*big.Int, common.Address, common.Hash, uint64, *big.Int, error) {
Expand Down
5 changes: 2 additions & 3 deletions arbos/l1pricing/l1pricing.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,14 @@ const (
const (
InitialInertia = 10
InitialPerUnitReward = 10
InitialPricePerUnitWei = 50 * params.GWei
InitialPerBatchGasCostV6 = 100000
)

// one minute at 100000 bytes / sec
var InitialEquilibrationUnitsV0 = arbmath.UintToBig(60 * params.TxDataNonZeroGasEIP2028 * 100000)
var InitialEquilibrationUnitsV6 = arbmath.UintToBig(params.TxDataNonZeroGasEIP2028 * 10000000)

func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient common.Address) error {
func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient common.Address, initialL1BaseFee *big.Int) error {
bptStorage := sto.OpenSubStorage(BatchPosterTableKey)
if err := InitializeBatchPostersTable(bptStorage); err != nil {
return err
Expand All @@ -109,7 +108,7 @@ func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient comm
return err
}
pricePerUnit := sto.OpenStorageBackedBigInt(pricePerUnitOffset)
if err := pricePerUnit.SetByUint(InitialPricePerUnitWei); err != nil {
if err := pricePerUnit.SetSaturatingWithWarning(initialL1BaseFee, "initial L1 base fee (storing in price per unit)"); err != nil {
return err
}
return nil
Expand Down
8 changes: 4 additions & 4 deletions arbos/l1pricing/l1pricing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
package l1pricing

import (
"math/big"
"testing"

am "github.com/offchainlabs/nitro/util/arbmath"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
"github.com/offchainlabs/nitro/arbos/burn"
"github.com/offchainlabs/nitro/arbos/storage"
)

func TestL1PriceUpdate(t *testing.T) {
sto := storage.NewMemoryBacked(burn.NewSystemBurner(nil, false))
err := InitializeL1PricingState(sto, common.Address{})
initialPriceEstimate := big.NewInt(123 * params.GWei)
err := InitializeL1PricingState(sto, common.Address{}, initialPriceEstimate)
Require(t, err)
ps := OpenL1PricingState(sto)

Expand All @@ -25,7 +26,6 @@ func TestL1PriceUpdate(t *testing.T) {
Fail(t)
}

initialPriceEstimate := am.UintToBig(InitialPricePerUnitWei)
priceEstimate, err := ps.PricePerUnit()
Require(t, err)
if priceEstimate.Cmp(initialPriceEstimate) != 0 {
Expand Down
8 changes: 8 additions & 0 deletions arbos/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ func HashFromReader(rd io.Reader) (common.Hash, error) {
return common.BytesToHash(buf), nil
}

func Uint256FromReader(rd io.Reader) (*big.Int, error) {
asHash, err := HashFromReader(rd)
if err != nil {
return nil, err
}
return asHash.Big(), nil
}

func HashToWriter(val common.Hash, wr io.Writer) error {
_, err := wr.Write(val.Bytes())
return err
Expand Down
28 changes: 16 additions & 12 deletions cmd/nitro/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo
if config.Init.ThenQuit {
cacheConfig.SnapshotWait = true
}
var serializedChainConfig []byte
var parsedInitMessage *arbostypes.ParsedInitMessage
if config.Node.L1Reader.Enable {
delayedBridge, err := arbnode.NewDelayedBridge(l1Client, rollupAddrs.Bridge, rollupAddrs.DeployedAt)
if err != nil {
Expand All @@ -596,30 +596,34 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo
if initMessage == nil {
return chainDb, nil, fmt.Errorf("failed to get init message while attempting to get serialized chain config")
}
var initChainConfig *params.ChainConfig
var initChainId *big.Int
initChainId, initChainConfig, serializedChainConfig, err = initMessage.ParseInitMessage()
parsedInitMessage, err = initMessage.ParseInitMessage()
if err != nil {
return chainDb, nil, err
}
if initChainId.Cmp(chainId) != 0 {
return chainDb, nil, fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", chainId, initChainId)
if parsedInitMessage.ChainId.Cmp(chainId) != 0 {
return chainDb, nil, fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", chainId, parsedInitMessage.ChainId)
}
if initChainConfig != nil {
if err := initChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil {
if parsedInitMessage.ChainConfig != nil {
if err := parsedInitMessage.ChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil {
return chainDb, nil, fmt.Errorf("incompatible chain config read from init message in L1 inbox: %w", err)
}
}
log.Info("Read serialized chain config from init message", "json", string(serializedChainConfig))
log.Info("Read serialized chain config from init message", "json", string(parsedInitMessage.SerializedChainConfig))
} else {
serializedChainConfig, err = json.Marshal(chainConfig)
serializedChainConfig, err := json.Marshal(chainConfig)
if err != nil {
return chainDb, nil, err
}
log.Warn("Serialized chain config as L1Reader is disabled and serialized chain config from init message is not available", "json", string(serializedChainConfig))
parsedInitMessage = &arbostypes.ParsedInitMessage{
ChainId: chainConfig.ChainID,
InitialL1BaseFee: arbostypes.DefaultInitialL1BaseFee,
ChainConfig: chainConfig,
SerializedChainConfig: serializedChainConfig,
}
log.Warn("Created fake init message as L1Reader is disabled and serialized chain config from init message is not available", "json", string(serializedChainConfig))
}

l2BlockChain, err = execution.WriteOrTestBlockChain(chainDb, cacheConfig, initDataReader, chainConfig, serializedChainConfig, config.Node.TxLookupLimit, config.Init.AccountsPerSync)
l2BlockChain, err = execution.WriteOrTestBlockChain(chainDb, cacheConfig, initDataReader, chainConfig, parsedInitMessage, config.Node.TxLookupLimit, config.Init.AccountsPerSync)
if err != nil {
return chainDb, nil, err
}
Expand Down
Loading

0 comments on commit 152b9ff

Please sign in to comment.