diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index ac696f446be6..bfb20954666c 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -812,6 +812,7 @@ func (m callMsg) Gas() uint64 { return m.CallMsg.Gas } func (m callMsg) Value() *big.Int { return m.CallMsg.Value } func (m callMsg) Data() []byte { return m.CallMsg.Data } func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList } +func (m callMsg) DataHashes() []common.Hash { return m.CallMsg.DataHashes } // filterBackend implements filters.Backend to support filtering for logs without // taking bloom-bits acceleration structures into account. diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 6f1c964ada02..78a2b58a932d 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -139,7 +139,7 @@ func Transaction(ctx *cli.Context) error { r.Address = sender } // Check intrinsic gas - if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, + if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), len(tx.BlobVersionedHashes()), tx.To() == nil, chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil { r.Error = err results = append(results, r) diff --git a/core/bench_test.go b/core/bench_test.go index 959979763d66..0792892669c8 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { return func(i int, gen *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) - gas, _ := IntrinsicGas(data, nil, false, false, false) + gas, _ := IntrinsicGas(data, nil, 0, false, false, false) signer := types.MakeSigner(gen.config, big.NewInt(int64(i))) gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 37a1a42d0c60..6317c33c289c 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -41,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/protolambda/ztyp/view" ) // So we can deterministically seed different blockchains @@ -3704,3 +3705,87 @@ func TestEIP1559Transition(t *testing.T) { t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) } } + +// TestDataBlobTxs tests the following: +// +// 1. Writes data hash from transaction to storage. +func TestDataBlobTxs(t *testing.T) { + var ( + one = common.Hash{1} + two = common.Hash{2} + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + + // Generate a canonical chain to act as the main dataset + engine = ethash.NewFaker() + db = rawdb.NewMemoryDatabase() + + // A sender who makes transactions, has some funds + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + gspec = &Genesis{ + Config: params.AllEthashProtocolChanges, + Alloc: GenesisAlloc{ + addr1: {Balance: funds}, + // The address 0xAAAA writes dataHashes[1] to storage slot 0x0. + aa: { + Code: []byte{ + byte(vm.PUSH1), + byte(0x1), + byte(vm.DATAHASH), + byte(vm.PUSH1), + byte(0x0), + byte(vm.SSTORE), + }, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + ) + + gspec.Config.BerlinBlock = common.Big0 + gspec.Config.LondonBlock = common.Big0 + gspec.Config.ShardingForkBlock = common.Big0 + genesis := gspec.MustCommit(db) + signer := types.LatestSigner(gspec.Config) + + blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + msg := types.BlobTxMessage{ + Nonce: 0, + Gas: 500000, + } + msg.To.Address = (*types.AddressSSZ)(&aa) + msg.ChainID.SetFromBig((*big.Int)(gspec.Config.ChainID)) + msg.Nonce = view.Uint64View(0) + msg.GasFeeCap.SetFromBig(newGwei(5)) + msg.GasTipCap.SetFromBig(big.NewInt(2)) + msg.BlobVersionedHashes = []common.Hash{one, two} + txdata := &types.SignedBlobTx{Message: msg} + + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + }) + + diskdb := rawdb.NewMemoryDatabase() + gspec.MustCommit(diskdb) + + chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + state, _ := chain.State() + + // 1. Check that the storage slot is set to dataHashes[1]. + actual := state.GetState(aa, common.Hash{0}) + if actual != two { + t.Fatalf("incorrect data hash written to state (want: %s, got: %s)", two, actual) + } +} diff --git a/core/evm.go b/core/evm.go index 536ac673e6a6..83a0de5140a0 100644 --- a/core/evm.go +++ b/core/evm.go @@ -72,8 +72,9 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common // NewEVMTxContext creates a new transaction context for a single transaction. func NewEVMTxContext(msg Message) vm.TxContext { return vm.TxContext{ - Origin: msg.From(), - GasPrice: new(big.Int).Set(msg.GasPrice()), + Origin: msg.From(), + GasPrice: new(big.Int).Set(msg.GasPrice()), + DataHashes: msg.DataHashes(), } } diff --git a/core/state_transition.go b/core/state_transition.go index 05d5633075b9..14053a1b9104 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -77,6 +77,7 @@ type Message interface { IsFake() bool Data() []byte AccessList() types.AccessList + DataHashes() []common.Hash } // ExecutionResult includes all output after executing given evm @@ -115,7 +116,7 @@ func (result *ExecutionResult) Revert() []byte { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) { +func IntrinsicGas(data []byte, accessList types.AccessList, blobCount int, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if isContractCreation && isHomestead { @@ -152,6 +153,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b gas += uint64(len(accessList)) * params.TxAccessListAddressGas gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas } + gas += uint64(blobCount) * params.BlobGas return gas, nil } @@ -295,7 +297,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { contractCreation := msg.To() == nil // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) + gas, err := IntrinsicGas(st.data, st.msg.AccessList(), len(st.msg.DataHashes()), contractCreation, homestead, istanbul) if err != nil { return nil, err } diff --git a/core/tx_pool.go b/core/tx_pool.go index 3329d736a37f..7f0663c3babc 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -635,7 +635,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrInsufficientFunds } // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) + intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), 0, tx.To() == nil, true, pool.istanbul) if err != nil { return err } diff --git a/core/types/data_blob_tx.go b/core/types/data_blob_tx.go index 0592090fa51e..0dc30d3e217a 100644 --- a/core/types/data_blob_tx.go +++ b/core/types/data_blob_tx.go @@ -4,13 +4,14 @@ import ( "encoding/hex" "errors" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" "github.com/protolambda/ztyp/codec" "github.com/protolambda/ztyp/conv" "github.com/protolambda/ztyp/tree" . "github.com/protolambda/ztyp/view" - "math/big" ) type ECDSASignature struct { @@ -432,6 +433,6 @@ func (stx *SignedBlobTx) rawSignatureValues() (v, r, s *big.Int) { func (stx *SignedBlobTx) setSignatureValues(chainID, v, r, s *big.Int) { (*uint256.Int)(&stx.Message.ChainID).SetFromBig(chainID) stx.Signature.V = Uint8View(v.Uint64()) - (*uint256.Int)(&stx.Signature.R).SetFromBig(chainID) - (*uint256.Int)(&stx.Signature.S).SetFromBig(chainID) + (*uint256.Int)(&stx.Signature.R).SetFromBig(r) + (*uint256.Int)(&stx.Signature.S).SetFromBig(s) } diff --git a/core/types/transaction.go b/core/types/transaction.go index 3d7bdb0cc1b2..2b388019360c 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -20,12 +20,13 @@ import ( "bytes" "container/heap" "errors" - "github.com/protolambda/ztyp/codec" "io" "math/big" "sync/atomic" "time" + "github.com/protolambda/ztyp/codec" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" @@ -596,6 +597,7 @@ type Message struct { gasTipCap *big.Int data []byte accessList AccessList + dataHashes []common.Hash isFake bool } @@ -627,6 +629,7 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) { amount: tx.Value(), data: tx.Data(), accessList: tx.AccessList(), + dataHashes: tx.BlobVersionedHashes(), isFake: false, } // If baseFee provided, set gasPrice to effectiveGasPrice. @@ -638,17 +641,18 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) { return msg, err } -func (m Message) From() common.Address { return m.from } -func (m Message) To() *common.Address { return m.to } -func (m Message) GasPrice() *big.Int { return m.gasPrice } -func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap } -func (m Message) GasTipCap() *big.Int { return m.gasTipCap } -func (m Message) Value() *big.Int { return m.amount } -func (m Message) Gas() uint64 { return m.gasLimit } -func (m Message) Nonce() uint64 { return m.nonce } -func (m Message) Data() []byte { return m.data } -func (m Message) AccessList() AccessList { return m.accessList } -func (m Message) IsFake() bool { return m.isFake } +func (m Message) From() common.Address { return m.from } +func (m Message) To() *common.Address { return m.to } +func (m Message) GasPrice() *big.Int { return m.gasPrice } +func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap } +func (m Message) GasTipCap() *big.Int { return m.gasTipCap } +func (m Message) Value() *big.Int { return m.amount } +func (m Message) Gas() uint64 { return m.gasLimit } +func (m Message) Nonce() uint64 { return m.nonce } +func (m Message) Data() []byte { return m.data } +func (m Message) AccessList() AccessList { return m.accessList } +func (m Message) DataHashes() []common.Hash { return m.dataHashes } +func (m Message) IsFake() bool { return m.isFake } // copyAddressPtr copies an address. func copyAddressPtr(a *common.Address) *common.Address { diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 919e9e5ccba2..e6fa6a37f691 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -40,6 +40,8 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { var signer Signer switch { + case config.IsSharding(blockNumber): + signer = NewDankSigner(config.ChainID) case config.IsLondon(blockNumber): signer = NewLondonSigner(config.ChainID) case config.IsBerlin(blockNumber): @@ -63,6 +65,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { // have the current block number available, use MakeSigner instead. func LatestSigner(config *params.ChainConfig) Signer { if config.ChainID != nil { + if config.ShardingForkBlock != nil { + return NewDankSigner(config.ChainID) + } if config.LondonBlock != nil { return NewLondonSigner(config.ChainID) } diff --git a/core/vm/eips.go b/core/vm/eips.go index 4070a2db5342..2043d56ee751 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -174,3 +174,26 @@ func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] scope.Stack.push(baseFee) return nil, nil } + +// enable3198 applies mini-danksharding (DATAHASH Opcode) +// - Adds an opcode that returns the versioned data hash of the tx at a index. +func enableSharding(jt *JumpTable) { + jt[DATAHASH] = &operation{ + execute: opDataHash, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } +} + +// opDataHash implements DATAHASH opcode +func opDataHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + idx := scope.Stack.pop() + if uint64(len(interpreter.evm.TxContext.DataHashes)) < idx.Uint64() { + scope.Stack.push(uint256.NewInt(0)) + } else { + hash := interpreter.evm.TxContext.DataHashes[idx.Uint64()] + scope.Stack.push(new(uint256.Int).SetBytes(hash.Bytes())) + } + return nil, nil +} diff --git a/core/vm/evm.go b/core/vm/evm.go index dd55618bf812..fcf5d75dbde3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -82,8 +82,9 @@ type BlockContext struct { // All fields can change between transactions. type TxContext struct { // Message information - Origin common.Address // Provides information for ORIGIN - GasPrice *big.Int // Provides information for GASPRICE + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE + DataHashes []common.Hash // Provides versioned data hashes for DATAHASH } // EVM is the Ethereum Virtual Machine base object and provides diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 36589a126957..a0a6de28f33a 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -688,3 +688,44 @@ func TestRandom(t *testing.T) { } } } + +func TestDataHash(t *testing.T) { + type testcase struct { + name string + idx uint64 + expect common.Hash + hashes []common.Hash + } + var ( + zero = common.Hash{0} + one = common.Hash{1} + two = common.Hash{2} + three = common.Hash{3} + ) + for _, tt := range []testcase{ + {name: "[{1}]", idx: 0, expect: one, hashes: []common.Hash{one}}, + {name: "[1,{2},3]", idx: 2, expect: three, hashes: []common.Hash{one, two, three}}, + {name: "out-of-bounds (empty)", idx: 10, expect: zero, hashes: []common.Hash{}}, + {name: "out-of-bounds", idx: 25, expect: zero, hashes: []common.Hash{one, two, three}}, + } { + var ( + env = NewEVM(BlockContext{}, TxContext{DataHashes: tt.hashes}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) + evmInterpreter = env.interpreter + ) + stack.push(uint256.NewInt(tt.idx)) + opDataHash(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) + if len(stack.data) != 1 { + t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) + } + actual := stack.pop() + expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.expect.Bytes())) + if overflow { + t.Errorf("Testcase %v: invalid overflow", tt.name) + } + if actual.Cmp(expected) != 0 { + t.Errorf("Testcase %v: expected %x, got %x", tt.name, expected, actual) + } + } +} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 21e3c914e139..bf1e44b7f1fa 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -69,6 +69,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // If jump table was not initialised we set the default one. if cfg.JumpTable == nil { switch { + case evm.chainRules.IsSharding: + cfg.JumpTable = &shardingInstructionSet case evm.chainRules.IsMerge: cfg.JumpTable = &mergeInstructionSet case evm.chainRules.IsLondon: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index eef3b53d8c66..582dc98ecdcd 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -55,6 +55,7 @@ var ( berlinInstructionSet = newBerlinInstructionSet() londonInstructionSet = newLondonInstructionSet() mergeInstructionSet = newMergeInstructionSet() + shardingInstructionSet = newShardingInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. @@ -78,6 +79,12 @@ func validate(jt JumpTable) JumpTable { return jt } +func newShardingInstructionSet() JumpTable { + instructionSet := newLondonInstructionSet() + enableSharding(&instructionSet) + return validate(instructionSet) +} + func newMergeInstructionSet() JumpTable { instructionSet := newLondonInstructionSet() instructionSet[RANDOM] = &operation{ diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index ba70fa09d486..9cdbb744f385 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -100,6 +100,7 @@ const ( CHAINID OpCode = 0x46 SELFBALANCE OpCode = 0x47 BASEFEE OpCode = 0x48 + DATAHASH OpCode = 0x49 ) // 0x50 range - 'storage' and execution. @@ -281,6 +282,7 @@ var opCodeToString = map[OpCode]string{ CHAINID: "CHAINID", SELFBALANCE: "SELFBALANCE", BASEFEE: "BASEFEE", + DATAHASH: "DATAHASH", // 0x50 range - 'storage' and execution. POP: "POP", @@ -431,6 +433,7 @@ var stringToOp = map[string]OpCode{ "CALLDATACOPY": CALLDATACOPY, "CHAINID": CHAINID, "BASEFEE": BASEFEE, + "DATAHASH": DATAHASH, "DELEGATECALL": DELEGATECALL, "STATICCALL": STATICCALL, "CODESIZE": CODESIZE, diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 30c5c2cf149a..74070e9f2bd0 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -703,7 +703,7 @@ func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad // Compute intrinsic gas isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul) + intrinsicGas, err := core.IntrinsicGas(input, nil, 0, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul) if err != nil { return } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 598663ac81c0..570f6d1fa2d6 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -66,7 +66,7 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // Compute intrinsic gas isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul) + intrinsicGas, err := core.IntrinsicGas(input, nil, 0, create, isHomestead, isIstanbul) if err != nil { return } diff --git a/interfaces.go b/interfaces.go index 76c1ef6908f2..cd45b1556b1d 100644 --- a/interfaces.go +++ b/interfaces.go @@ -142,6 +142,7 @@ type CallMsg struct { Data []byte // input data, usually an ABI-encoded contract method invocation AccessList types.AccessList // EIP-2930 access list. + DataHashes []common.Hash // versioned data hashes for mini-danksharding } // A ContractCaller provides contract calls, essentially transactions that are executed by diff --git a/light/txpool.go b/light/txpool.go index a7df4aeec388..b46e2d899bc8 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -382,7 +382,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should supply enough intrinsic gas - gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) + gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), 0, tx.To() == nil, true, pool.istanbul) if err != nil { return err } diff --git a/params/config.go b/params/config.go index 7f52472ec9dc..caac0d71eec2 100644 --- a/params/config.go +++ b/params/config.go @@ -257,16 +257,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int), false) ) @@ -347,6 +347,7 @@ type ChainConfig struct { LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london) ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) MergeForkBlock *big.Int `json:"mergeForkBlock,omitempty"` // EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge proceedings) + ShardingForkBlock *big.Int `json:"shardingForkBlock,omitempty"` // Mini-Danksharding switch block (nil = no fork, 0 = already activated) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -387,7 +388,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, Engine: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, ShardingFork: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -404,6 +405,7 @@ func (c *ChainConfig) String() string { c.LondonBlock, c.ArrowGlacierBlock, c.MergeForkBlock, + c.ShardingForkBlock, engine, ) } @@ -475,6 +477,11 @@ func (c *ChainConfig) IsArrowGlacier(num *big.Int) bool { return isForked(c.ArrowGlacierBlock, num) } +// IsSharding returns whether num is either equal to the Mini-Danksharding fork block or greater. +func (c *ChainConfig) IsSharding(num *big.Int) bool { + return isForked(c.ShardingForkBlock, num) +} + // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool { if c.TerminalTotalDifficulty == nil { @@ -525,6 +532,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "londonBlock", block: c.LondonBlock}, {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, {name: "mergeStartBlock", block: c.MergeForkBlock, optional: true}, + {name: "shardingForkBlock", block: c.ShardingForkBlock, optional: true}, } { if lastFork.name != "" { // Next one must be higher number @@ -600,6 +608,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.MergeForkBlock, newcfg.MergeForkBlock, head) { return newCompatError("Merge Start fork block", c.MergeForkBlock, newcfg.MergeForkBlock) } + if isForkIncompatible(c.ShardingForkBlock, newcfg.ShardingForkBlock, head) { + return newCompatError("Mini-Danksharding fork block", c.ShardingForkBlock, newcfg.ShardingForkBlock) + } return nil } @@ -669,6 +680,7 @@ type Rules struct { IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool IsMerge bool + IsSharding bool } // Rules ensures c's ChainID is not nil. @@ -690,5 +702,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool) Rules { IsBerlin: c.IsBerlin(num), IsLondon: c.IsLondon(num), IsMerge: isMerge, + IsSharding: c.IsSharding(num), } } diff --git a/params/protocol_params.go b/params/protocol_params.go index 5f154597a7fa..34d1c01e9778 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -157,6 +157,9 @@ const ( // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 RefundQuotient uint64 = 2 RefundQuotientEIP3529 uint64 = 5 + + // Fixed cost for sending a data blob. + BlobGas uint64 = 120000 ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 82ee01de15c8..897570260864 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -55,7 +55,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul) + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), len(tx.BlobVersionedHashes()), tx.To() == nil, isHomestead, isIstanbul) if err != nil { return nil, nil, err }