Skip to content
Open
85 changes: 85 additions & 0 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
type PrecompiledContract interface {
RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
Name() string
}

// PrecompiledContracts contains the precompiled contracts supported at the given fork.
Expand Down Expand Up @@ -309,6 +310,10 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil
}

func (c *ecrecover) Name() string {
return "ECREC"
}

// SHA256 implemented as a native contract.
type sha256hash struct{}

Expand All @@ -324,6 +329,10 @@ func (c *sha256hash) Run(input []byte) ([]byte, error) {
return h[:], nil
}

func (c *sha256hash) Name() string {
return "SHA256"
}

// RIPEMD160 implemented as a native contract.
type ripemd160hash struct{}

Expand All @@ -340,6 +349,10 @@ func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
}

func (c *ripemd160hash) Name() string {
return "RIPEMD160"
}

// data copy implemented as a native contract.
type dataCopy struct{}

Expand All @@ -354,6 +367,10 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) {
return common.CopyBytes(in), nil
}

func (c *dataCopy) Name() string {
return "ID"
}

// bigModExp implements a native big integer exponential modular operation.
type bigModExp struct {
eip2565 bool
Expand Down Expand Up @@ -543,6 +560,10 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
return common.LeftPadBytes(v, int(modLen)), nil
}

func (c *bigModExp) Name() string {
return "MODEXP"
}

// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point,
// returning it, or an error if the point is invalid.
func newCurvePoint(blob []byte) (*bn256.G1, error) {
Expand Down Expand Up @@ -592,6 +613,10 @@ func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) {
return runBn256Add(input)
}

func (c *bn256AddIstanbul) Name() string {
return "BN254_ADD"
}

// bn256AddByzantium implements a native elliptic curve point addition
// conforming to Byzantium consensus rules.
type bn256AddByzantium struct{}
Expand All @@ -605,6 +630,10 @@ func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) {
return runBn256Add(input)
}

func (c *bn256AddByzantium) Name() string {
return "BN254_ADD"
}

// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by
// both Byzantium and Istanbul operations.
func runBn256ScalarMul(input []byte) ([]byte, error) {
Expand All @@ -630,6 +659,10 @@ func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) {
return runBn256ScalarMul(input)
}

func (c *bn256ScalarMulIstanbul) Name() string {
return "BN254_MUL"
}

// bn256ScalarMulByzantium implements a native elliptic curve scalar
// multiplication conforming to Byzantium consensus rules.
type bn256ScalarMulByzantium struct{}
Expand All @@ -643,6 +676,10 @@ func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) {
return runBn256ScalarMul(input)
}

func (c *bn256ScalarMulByzantium) Name() string {
return "BN254_MUL"
}

var (
// true32Byte is returned if the bn256 pairing check succeeds.
true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
Expand Down Expand Up @@ -698,6 +735,10 @@ func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
return runBn256Pairing(input)
}

func (c *bn256PairingIstanbul) Name() string {
return "BN254_PAIRING"
}

// bn256PairingByzantium implements a pairing pre-compile for the bn256 curve
// conforming to Byzantium consensus rules.
type bn256PairingByzantium struct{}
Expand All @@ -711,6 +752,10 @@ func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) {
return runBn256Pairing(input)
}

func (c *bn256PairingByzantium) Name() string {
return "BN254_PAIRING"
}

type blake2F struct{}

func (c *blake2F) RequiredGas(input []byte) uint64 {
Expand Down Expand Up @@ -772,6 +817,10 @@ func (c *blake2F) Run(input []byte) ([]byte, error) {
return output, nil
}

func (c *blake2F) Name() string {
return "BLAKE2F"
}

var (
errBLS12381InvalidInputLength = errors.New("invalid input length")
errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes")
Expand Down Expand Up @@ -815,6 +864,10 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
return encodePointG1(p0), nil
}

func (c *bls12381G1Add) Name() string {
return "BLS12_G1ADD"
}

// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
type bls12381G1MultiExp struct{}

Expand Down Expand Up @@ -875,6 +928,10 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
return encodePointG1(r), nil
}

func (c *bls12381G1MultiExp) Name() string {
return "BLS12_G1MSM"
}

// bls12381G2Add implements EIP-2537 G2Add precompile.
type bls12381G2Add struct{}

Expand Down Expand Up @@ -912,6 +969,10 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
return encodePointG2(r), nil
}

func (c *bls12381G2Add) Name() string {
return "BLS12_G2ADD"
}

// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
type bls12381G2MultiExp struct{}

Expand Down Expand Up @@ -972,6 +1033,10 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
return encodePointG2(r), nil
}

func (c *bls12381G2MultiExp) Name() string {
return "BLS12_G2MSM"
}

// bls12381Pairing implements EIP-2537 Pairing precompile.
type bls12381Pairing struct{}

Expand Down Expand Up @@ -1035,6 +1100,10 @@ func (c *bls12381Pairing) Run(input []byte) ([]byte, error) {
return out, nil
}

func (c *bls12381Pairing) Name() string {
return "BLS12_PAIRING_CHECK"
}

func decodePointG1(in []byte) (*bls12381.G1Affine, error) {
if len(in) != 128 {
return nil, errors.New("invalid g1 point length")
Expand Down Expand Up @@ -1153,6 +1222,10 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
return encodePointG1(&r), nil
}

func (c *bls12381MapG1) Name() string {
return "BLS12_MAP_FP_TO_G1"
}

// bls12381MapG2 implements EIP-2537 MapG2 precompile.
type bls12381MapG2 struct{}

Expand Down Expand Up @@ -1186,6 +1259,10 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
return encodePointG2(&r), nil
}

func (c *bls12381MapG2) Name() string {
return "BLS12_MAP_FP2_TO_G2"
}

// kzgPointEvaluation implements the EIP-4844 point evaluation precompile.
type kzgPointEvaluation struct{}

Expand Down Expand Up @@ -1242,6 +1319,10 @@ func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) {
return common.Hex2Bytes(blobPrecompileReturnValue), nil
}

func (b *kzgPointEvaluation) Name() string {
return "KZG_POINT_EVALUATION"
}

// kZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
h := sha256.Sum256(kzg[:])
Expand Down Expand Up @@ -1277,3 +1358,7 @@ func (c *p256Verify) Run(input []byte) ([]byte, error) {
}
return nil, nil
}

func (c *p256Verify) Name() string {
return "P256VERIFY"
}
61 changes: 61 additions & 0 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/forkid"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
Expand Down Expand Up @@ -1153,6 +1154,66 @@ func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args Transaction
return result, nil
}

type config struct {
ActivationTime uint64 `json:"activationTime"`
BlobSchedule *params.BlobConfig `json:"blobSchedule"`
ChainId *hexutil.Big `json:"chainId"`
ForkId hexutil.Bytes `json:"forkId"`
Precompiles map[string]common.Address `json:"precompiles"`
SystemContracts map[string]common.Address `json:"systemContracts"`
}

type configResponse struct {
Current *config `json:"current"`
Next *config `json:"next"`
Last *config `json:"last"`
}

// Config implements the EIP-7910 eth_config method.
func (api *BlockChainAPI) Config(ctx context.Context) (*configResponse, error) {
genesis, err := api.b.HeaderByNumber(ctx, 0)
if err != nil {
return nil, fmt.Errorf("unable to load genesis: %w", err)
}
assemble := func(c *params.ChainConfig, ts *uint64) *config {
if ts == nil {
return nil
}
t := *ts

var (
rules = c.Rules(c.LondonBlock, true, t)
precompiles = make(map[string]common.Address)
)
for addr, c := range vm.ActivePrecompiledContracts(rules) {
precompiles[c.Name()] = addr
}
forkid := forkid.NewID(c, types.NewBlockWithHeader(genesis), ^uint64(0), t).Hash
return &config{
ActivationTime: t,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Activation time is required. If a fork is activated at genesis the value 0 is used. If the fork is not scheduled to be activated or its activation time is unknown it should not be in the rpc results.

Fix like this?

diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index eb662f9a71..9f2e84c194 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -1188,9 +1188,14 @@ func (api *BlockChainAPI) Config(ctx context.Context) (*configResponse, error) {
 		for addr, c := range vm.ActivePrecompiledContracts(rules) {
 			precompiles[c.Name()] = addr
 		}
+		// Activation time is required. If a fork is activated at genesis the value 0 is used
+		activateTime := t
+		if genesis.Time >= t {
+			activateTime = 0
+		}
 		forkid := forkid.NewID(c, types.NewBlockWithHeader(genesis), ^uint64(0), t).Hash
 		return &config{
-			ActivationTime:  t,
+			ActivationTime:  activateTime,
 			BlobSchedule:    c.BlobConfig(c.LatestFork(t)),
 			ChainId:         (*hexutil.Big)(c.ChainID),
 			ForkId:          forkid[:],

BlobSchedule: c.BlobConfig(c.LatestFork(t)),
ChainId: (*hexutil.Big)(c.ChainID),
ForkId: forkid[:],
Precompiles: precompiles,
SystemContracts: c.ActiveSystemContracts(t),
}
}
var (
c = api.b.ChainConfig()
t = api.b.CurrentHeader().Time
)
resp := configResponse{
Next: assemble(c, c.Timestamp(c.LatestFork(t)+1)),
Current: assemble(c, c.Timestamp(c.LatestFork(t))),
Last: assemble(c, c.Timestamp(c.LatestFork(^uint64(0)))),
}
// Nil out last if no future-fork is configured.
if resp.Next == nil {
resp.Last = nil
}
return &resp, nil
}

// AccessList creates an access list for the given transaction.
// If the accesslist creation fails an error is returned.
// If the transaction itself fails, an vmErr is returned.
Expand Down
85 changes: 85 additions & 0 deletions internal/ethapi/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3767,3 +3767,88 @@ func TestEstimateGasWithMovePrecompile(t *testing.T) {
t.Fatalf("mismatched gas: %d, want 21366", gas)
}
}

func TestEIP7910Config(t *testing.T) {
var (
newUint64 = func(val uint64) *uint64 { return &val }
// Define a snapshot of the current Hoodi config (only Prague scheduled) so that future forks do not
// cause this test to fail.
config = &params.ChainConfig{
ChainID: big.NewInt(560048),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: nil,
GrayGlacierBlock: nil,
TerminalTotalDifficulty: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
ShanghaiTime: newUint64(0),
CancunTime: newUint64(0),
PragueTime: newUint64(1742999832),
DepositContractAddress: common.HexToAddress("0x00000000219ab540356cBB839Cbe05303d7705Fa"),
Ethash: new(params.EthashConfig),
BlobScheduleConfig: &params.BlobScheduleConfig{
Cancun: params.DefaultCancunBlobConfig,
Prague: params.DefaultPragueBlobConfig,
},
}
)
gspec := core.DefaultHoodiGenesisBlock()
gspec.Config = config

var testSuite = []struct {
time uint64
file string
}{
{
time: 0,
file: "next-and-last",
},
{
time: *gspec.Config.PragueTime,
file: "current",
},
}

for i, tt := range testSuite {
backend := configTimeBackend{nil, gspec, tt.time}
api := NewBlockChainAPI(backend)
result, err := api.Config(context.Background())
if err != nil {
t.Errorf("test %d: want no error, have %v", i, err)
continue
}
testRPCResponseWithFile(t, i, result, "eth_config", tt.file)
}
}

type configTimeBackend struct {
*testBackend
genesis *core.Genesis
time uint64
}

func (b configTimeBackend) ChainConfig() *params.ChainConfig {
return b.genesis.Config
}

func (b configTimeBackend) HeaderByNumber(_ context.Context, n rpc.BlockNumber) (*types.Header, error) {
if n == 0 {
return b.genesis.ToBlock().Header(), nil
}
panic("not implemented")
}

func (b configTimeBackend) CurrentHeader() *types.Header {
return &types.Header{Time: b.time}
}
Loading