diff --git a/api/api_eth.go b/api/api_eth.go
index 901df8afa..a888c21b0 100644
--- a/api/api_eth.go
+++ b/api/api_eth.go
@@ -34,6 +34,7 @@ import (
"time"
"github.com/kaiachain/kaia/blockchain"
+ "github.com/kaiachain/kaia/blockchain/forkid"
"github.com/kaiachain/kaia/blockchain/state"
"github.com/kaiachain/kaia/blockchain/types"
"github.com/kaiachain/kaia/blockchain/vm"
@@ -1547,3 +1548,67 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
prevTracer = tracer
}
}
+
+type config struct {
+ // As mentioned in KIP-276, Kaia doesn't include ActivationTime as a field.
+ // 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 KIP-276(EIP-7910) eth_config method.
+func (api *EthAPI) Config(ctx context.Context) (*configResponse, error) {
+ b := api.kaiaBlockChainAPI.b
+ genesis, err := b.HeaderByNumber(ctx, 0)
+ if err != nil {
+ return nil, fmt.Errorf("unable to load genesis: %w", err)
+ }
+ assemble := func(c *params.ChainConfig, head *big.Int) *config {
+ if head == nil {
+ return nil
+ }
+
+ var (
+ rules = c.Rules(head)
+ precompiles = make(map[string]common.Address)
+ )
+ for addr, c := range vm.ActivePrecompiledContracts(rules) {
+ precompiles[c.Name()] = addr
+ }
+
+ id := forkid.NewID(c, genesis.Hash(), head.Uint64()).Hash
+ return &config{
+ BlobSchedule: c.BlobConfig(head.Uint64()),
+ ChainId: (*hexutil.Big)(c.ChainID),
+ ForkId: id[:],
+ Precompiles: precompiles,
+ SystemContracts: b.GetActiveSystemContracts(c, genesis.Hash(), head),
+ }
+ }
+ var (
+ c = b.ChainConfig()
+ bn = b.CurrentBlock().Number()
+ )
+ currentForkCompatibleBlock := forkid.LatestForkCompatibleBlock(c, bn)
+ nextForkCompatibleBlock := forkid.NextForkCompatibleBlock(c, bn)
+ lastForkCompatibleBlock := forkid.LastForkCompatibleBlock(c)
+ resp := configResponse{
+ Next: assemble(c, nextForkCompatibleBlock),
+ Current: assemble(c, currentForkCompatibleBlock),
+ Last: assemble(c, lastForkCompatibleBlock),
+ }
+ // Nil out last if no future-fork is configured.
+ if resp.Next == nil {
+ resp.Last = nil
+ }
+ return &resp, nil
+}
diff --git a/api/api_eth_test.go b/api/api_eth_test.go
index 3df0ddb92..43c86df32 100644
--- a/api/api_eth_test.go
+++ b/api/api_eth_test.go
@@ -16,6 +16,7 @@ import (
mock_accounts "github.com/kaiachain/kaia/accounts/mocks"
mock_api "github.com/kaiachain/kaia/api/mocks"
"github.com/kaiachain/kaia/blockchain"
+ "github.com/kaiachain/kaia/blockchain/forkid"
"github.com/kaiachain/kaia/blockchain/state"
"github.com/kaiachain/kaia/blockchain/types"
"github.com/kaiachain/kaia/blockchain/types/accountkey"
@@ -2688,3 +2689,163 @@ func TestEthAPI_EstimateGas(t *testing.T) {
return api.EstimateGas(context.Background(), args, nil, overrides)
})
}
+
+// TestEthAPI_Config tests the eth_config method.
+func TestEthAPI_Config(t *testing.T) {
+ expectedChainConfig := params.TestChainConfig
+ expectedChainConfig.IstanbulCompatibleBlock = big.NewInt(75373312)
+ expectedChainConfig.LondonCompatibleBlock = big.NewInt(80295291)
+ expectedChainConfig.PragueCompatibleBlock = big.NewInt(187930000)
+ genesisHeader := &types.Header{
+ Number: big.NewInt(0),
+ Root: common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
+ }
+ genesisForkID := forkid.NewID(expectedChainConfig, genesisHeader.Hash(), 0).Hash
+ istanbulForkID := forkid.NewID(expectedChainConfig, genesisHeader.Hash(), 75373312).Hash
+ lonondonForkID := forkid.NewID(expectedChainConfig, genesisHeader.Hash(), 80295291).Hash
+ pragueForkID := forkid.NewID(expectedChainConfig, genesisHeader.Hash(), 187930000).Hash
+ var (
+ genesisRules = expectedChainConfig.Rules(big.NewInt(0))
+ istanbulRules = expectedChainConfig.Rules(big.NewInt(75373312))
+ lonondonRules = expectedChainConfig.Rules(big.NewInt(80295291))
+ pragueRules = expectedChainConfig.Rules(big.NewInt(187930000))
+ genesisPrecompiles = make(map[string]common.Address)
+ istanbulPrecompiles = make(map[string]common.Address)
+ lonondonPrecompiles = make(map[string]common.Address)
+ praguePrecompiles = make(map[string]common.Address)
+ )
+ for addr, c := range vm.ActivePrecompiledContracts(genesisRules) {
+ genesisPrecompiles[c.Name()] = addr
+ }
+ for addr, c := range vm.ActivePrecompiledContracts(istanbulRules) {
+ istanbulPrecompiles[c.Name()] = addr
+ }
+ for addr, c := range vm.ActivePrecompiledContracts(lonondonRules) {
+ lonondonPrecompiles[c.Name()] = addr
+ }
+ for addr, c := range vm.ActivePrecompiledContracts(pragueRules) {
+ praguePrecompiles[c.Name()] = addr
+ }
+ tests := []struct {
+ name string
+ blockNumber uint64
+ expectedCurrent *config
+ expectedNext *config
+ expectedLast *config
+ }{
+ {
+ name: "Genesis block",
+ blockNumber: 0,
+ expectedCurrent: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: genesisForkID[:],
+ Precompiles: genesisPrecompiles,
+ SystemContracts: nil,
+ },
+ expectedNext: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: istanbulForkID[:],
+ Precompiles: istanbulPrecompiles,
+ SystemContracts: nil,
+ },
+ expectedLast: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: pragueForkID[:],
+ Precompiles: praguePrecompiles,
+ SystemContracts: nil,
+ },
+ },
+ {
+ name: "Istanbul block",
+ blockNumber: 75373312,
+ expectedCurrent: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: istanbulForkID[:],
+ Precompiles: istanbulPrecompiles,
+ SystemContracts: nil,
+ },
+ expectedNext: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: lonondonForkID[:],
+ Precompiles: lonondonPrecompiles,
+ SystemContracts: nil,
+ },
+ expectedLast: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: pragueForkID[:],
+ Precompiles: praguePrecompiles,
+ SystemContracts: nil,
+ },
+ },
+ {
+ name: "Latest fork block (Prague)",
+ blockNumber: 187930000,
+ expectedCurrent: &config{
+ BlobSchedule: nil,
+ ChainId: (*hexutil.Big)(expectedChainConfig.ChainID),
+ ForkId: pragueForkID[:],
+ Precompiles: praguePrecompiles,
+ SystemContracts: nil,
+ },
+ expectedNext: nil, // No more forks
+ expectedLast: nil, // Should be nil when Next is nil
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ mockCtrl, mockBackend, api := testInitForEthApi(t)
+ defer mockCtrl.Finish()
+
+ // Mock chain config
+ mockBackend.EXPECT().ChainConfig().Return(expectedChainConfig).AnyTimes()
+
+ // Mock genesis block (block 0) - this is called first in Config method
+ mockBackend.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Return(
+ genesisHeader,
+ nil,
+ )
+
+ // Mock current block - this is called after genesis
+ mockBackend.EXPECT().CurrentBlock().Return(
+ types.NewBlockWithHeader(&types.Header{Number: new(big.Int).SetUint64(tt.blockNumber)}),
+ )
+ mockBackend.EXPECT().GetActiveSystemContracts(gomock.Any(), gomock.Any(), gomock.Any()).Return(
+ nil,
+ ).AnyTimes()
+
+ // Call the method
+ config, err := api.Config(context.Background())
+ require.NoError(t, err)
+ require.NotNil(t, config)
+
+ // Validate configs
+ assert.Equal(t, tt.expectedCurrent, config.Current)
+ assert.Equal(t, tt.expectedNext, config.Next)
+ assert.Equal(t, tt.expectedLast, config.Last)
+ })
+ }
+}
+
+func TestEthAPI_Config_ErrorCases(t *testing.T) {
+ t.Run("Genesis block not found", func(t *testing.T) {
+ mockCtrl, mockBackend, api := testInitForEthApi(t)
+ defer mockCtrl.Finish()
+
+ mockBackend.EXPECT().ChainConfig().Return(params.KairosChainConfig).AnyTimes()
+ mockBackend.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Return(
+ nil, errors.New("genesis block not found"),
+ )
+
+ config, err := api.Config(context.Background())
+ assert.Error(t, err)
+ assert.Nil(t, config)
+ assert.Contains(t, err.Error(), "unable to load genesis")
+ })
+}
diff --git a/api/backend.go b/api/backend.go
index 9c1cf2f6e..edb0310ff 100644
--- a/api/backend.go
+++ b/api/backend.go
@@ -94,6 +94,7 @@ type Backend interface {
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
SubscribeNewTxsEvent(chan<- blockchain.NewTxsEvent) event.Subscription
+ GetActiveSystemContracts(c *params.ChainConfig, genesis common.Hash, head *big.Int) map[string]common.Address
ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block
diff --git a/api/mocks/backend_mock.go b/api/mocks/backend_mock.go
index c90ecf1c4..ab5cd0963 100644
--- a/api/mocks/backend_mock.go
+++ b/api/mocks/backend_mock.go
@@ -195,6 +195,20 @@ func (mr *MockBackendMockRecorder) FeeHistory(arg0, arg1, arg2, arg3 interface{}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockBackend)(nil).FeeHistory), arg0, arg1, arg2, arg3)
}
+// GetActiveSystemContracts mocks base method.
+func (m *MockBackend) GetActiveSystemContracts(arg0 *params.ChainConfig, arg1 common.Hash, arg2 *big.Int) map[string]common.Address {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetActiveSystemContracts", arg0, arg1, arg2)
+ ret0, _ := ret[0].(map[string]common.Address)
+ return ret0
+}
+
+// GetActiveSystemContracts indicates an expected call of GetActiveSystemContracts.
+func (mr *MockBackendMockRecorder) GetActiveSystemContracts(arg0, arg1, arg2 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveSystemContracts", reflect.TypeOf((*MockBackend)(nil).GetActiveSystemContracts), arg0, arg1, arg2)
+}
+
// GetBlockReceipts mocks base method.
func (m *MockBackend) GetBlockReceipts(arg0 context.Context, arg1 common.Hash) types.Receipts {
m.ctrl.T.Helper()
diff --git a/blockchain/forkid/forkid.go b/blockchain/forkid/forkid.go
new file mode 100644
index 000000000..79e41b3b3
--- /dev/null
+++ b/blockchain/forkid/forkid.go
@@ -0,0 +1,143 @@
+// Copyright 2025 The Kaia Authors
+// This file is part of the Kaia library.
+//
+// The Kaia library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The Kaia library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the Kaia library. If not, see .
+
+package forkid
+
+import (
+ "encoding/binary"
+ "hash/crc32"
+ "math/big"
+ "reflect"
+ "slices"
+ "strings"
+
+ "github.com/kaiachain/kaia/common"
+ "github.com/kaiachain/kaia/params"
+)
+
+// ID is a fork identifier as defined by EIP-2124.
+type ID struct {
+ Hash [4]byte // CRC32 checksum of the genesis block and passed fork block numbers
+ Next uint64 // Block number of the next upcoming fork, or 0 if no forks are known
+}
+
+// NewID calculates the Kaia fork ID from the chain config, genesis hash, head.
+func NewID(config *params.ChainConfig, genesis common.Hash, head uint64) ID {
+ // Calculate the starting checksum from the genesis hash
+ hash := crc32.ChecksumIEEE(genesis[:])
+
+ // Calculate the current fork checksum and the next fork block
+ var next uint64
+ for _, fork := range gatherForks(config) {
+ if fork <= head {
+ // Fork already passed, checksum the previous hash and the fork number
+ hash = checksumUpdate(hash, fork)
+ continue
+ }
+ next = fork
+ break
+ }
+ return ID{Hash: checksumToBytes(hash), Next: next}
+}
+
+// LatestForkCompatibleBlock returns the latest fork compatible block or genesis(0) if no forks are known.
+func LatestForkCompatibleBlock(config *params.ChainConfig, head *big.Int) *big.Int {
+ latestForkCompatibleBlock := common.Big0
+ for _, fork := range gatherForks(config) {
+ if new(big.Int).SetUint64(fork).Cmp(head) <= 0 {
+ latestForkCompatibleBlock = new(big.Int).SetUint64(fork)
+ continue
+ } else {
+ break
+ }
+ }
+ return latestForkCompatibleBlock
+}
+
+// NextForkCompatibleBlock returns the next fork compatible block or nil if no forks are known.
+func NextForkCompatibleBlock(config *params.ChainConfig, head *big.Int) *big.Int {
+ var nextForkCompatibleBlock *big.Int
+ for _, fork := range gatherForks(config) {
+ if new(big.Int).SetUint64(fork).Cmp(head) <= 0 {
+ continue
+ }
+ nextForkCompatibleBlock = new(big.Int).SetUint64(fork)
+ break
+ }
+ return nextForkCompatibleBlock
+}
+
+// LastForkCompatibleBlock returns the last fork compatible block or genesis(0) if no forks are known.
+func LastForkCompatibleBlock(config *params.ChainConfig) *big.Int {
+ forks := gatherForks(config)
+ if len(forks) == 0 {
+ return common.Big0
+ }
+ return new(big.Int).SetUint64(forks[len(forks)-1])
+}
+
+// checksumUpdate calculates the next IEEE CRC32 checksum based on the previous
+// one and a fork block number (equivalent to CRC32(original-blob || fork)).
+func checksumUpdate(hash uint32, fork uint64) uint32 {
+ var blob [8]byte
+ binary.BigEndian.PutUint64(blob[:], fork)
+ return crc32.Update(hash, crc32.IEEETable, blob[:])
+}
+
+// checksumToBytes converts a uint32 checksum into a [4]byte array.
+func checksumToBytes(hash uint32) [4]byte {
+ var blob [4]byte
+ binary.BigEndian.PutUint32(blob[:], hash)
+ return blob
+}
+
+// gatherForks gathers all the known forks and creates a sorted list out of them.
+func gatherForks(config *params.ChainConfig) []uint64 {
+ // Gather all the fork block numbers via reflection
+ kind := reflect.TypeFor[params.ChainConfig]()
+ conf := reflect.ValueOf(config).Elem()
+
+ var forks []uint64
+ for i := 0; i < kind.NumField(); i++ {
+ // Fetch the next field and skip non-fork rules
+ field := kind.Field(i)
+ if !strings.HasSuffix(field.Name, "CompatibleBlock") {
+ continue
+ }
+ if field.Type != reflect.TypeFor[*big.Int]() {
+ continue
+ }
+ // Extract the fork rule block number and aggregate it
+ rule := conf.Field(i).Interface().(*big.Int)
+ if rule != nil {
+ forks = append(forks, rule.Uint64())
+ }
+ }
+ // Sort the fork block numbers to permit chronologival XOR
+ slices.Sort(forks)
+ // Deduplicate block numbers applying multiple forks
+ for i := 1; i < len(forks); i++ {
+ if forks[i] == forks[i-1] {
+ forks = append(forks[:i], forks[i+1:]...)
+ i--
+ }
+ }
+ // Skip any forks in block 0, that's the genesis ruleset
+ if len(forks) > 0 && forks[0] == 0 {
+ forks = forks[1:]
+ }
+ return forks
+}
diff --git a/blockchain/forkid/forkid_test.go b/blockchain/forkid/forkid_test.go
new file mode 100644
index 000000000..6176bd911
--- /dev/null
+++ b/blockchain/forkid/forkid_test.go
@@ -0,0 +1,167 @@
+// Copyright 2025 The Kaia Authors
+// This file is part of the Kaia library.
+//
+// The Kaia library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The Kaia library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the Kaia library. If not, see .
+
+package forkid
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/kaiachain/kaia/common"
+ "github.com/kaiachain/kaia/params"
+)
+
+// TestCreation tests that different genesis and fork rule combinations result in
+// the correct fork ID.
+func TestCreation(t *testing.T) {
+ type testcase struct {
+ head uint64
+ want ID
+ }
+ tests := []struct {
+ config *params.ChainConfig
+ genesis common.Hash
+ cases []testcase
+ }{
+ // Mainnet test cases
+ {
+ params.MainnetChainConfig,
+ params.MainnetGenesisHash,
+ []testcase{
+ {0, ID{Hash: checksumToBytes(0xdd58eb45), Next: 86816005}}, // Unsynced
+ {86816004, ID{Hash: checksumToBytes(0xdd58eb45), Next: 86816005}}, // Last Genesis block
+ {86816005, ID{Hash: checksumToBytes(0x7b1131bb), Next: 99841497}}, // First Istanbul+London+EthTxType block
+ {99841496, ID{Hash: checksumToBytes(0x7b1131bb), Next: 99841497}}, // Last Istanbul+London+EthTxType block
+ {99841497, ID{Hash: checksumToBytes(0x8b3961e6), Next: 119750400}}, // First Magma block
+ {119750399, ID{Hash: checksumToBytes(0x8b3961e6), Next: 119750400}}, // Last Magma block
+ {119750400, ID{Hash: checksumToBytes(0x171d8904), Next: 135456000}}, // First Kore+Kip103 block
+ {135455999, ID{Hash: checksumToBytes(0x171d8904), Next: 135456000}}, // Last Kore+Kip103 block
+ {135456000, ID{Hash: checksumToBytes(0x68717c3d), Next: 147534000}}, // First Shanghai block
+ {147533999, ID{Hash: checksumToBytes(0x68717c3d), Next: 147534000}}, // Last Shanghai block
+ {147534000, ID{Hash: checksumToBytes(0x75771543), Next: 162900480}}, // First Cancun+Randao block
+ {162900479, ID{Hash: checksumToBytes(0x75771543), Next: 162900480}}, // Last Cancun+Randao block
+ {162900480, ID{Hash: checksumToBytes(0x3ab6dcda), Next: 190670000}}, // First Kaia+Kip160 block
+ {190669999, ID{Hash: checksumToBytes(0x3ab6dcda), Next: 190670000}}, // Last Kaia+Kip160 block
+ {190670000, ID{Hash: checksumToBytes(0xc00bab0e), Next: 0}}, // First Prague block
+ {198489578, ID{Hash: checksumToBytes(0xc00bab0e), Next: 0}}, // Today Prague block
+ },
+ },
+ // Kairos test cases
+ {
+ params.KairosChainConfig,
+ params.KairosGenesisHash,
+ []testcase{
+ {0, ID{Hash: checksumToBytes(0x5e10f192), Next: 75373312}}, // Unsynced
+ {9, ID{Hash: checksumToBytes(0x5e10f192), Next: 75373312}}, // Last Genesis block
+ {75373312, ID{Hash: checksumToBytes(0x3640372e), Next: 80295291}}, // First Istanbul block
+ {80295290, ID{Hash: checksumToBytes(0x3640372e), Next: 80295291}}, // Last Istanbul block
+ {80295291, ID{Hash: checksumToBytes(0xb1d92301), Next: 86513895}}, // First London block
+ {86513894, ID{Hash: checksumToBytes(0xb1d92301), Next: 86513895}}, // Last London block
+ {86513895, ID{Hash: checksumToBytes(0xf2be985d), Next: 98347376}}, // First EthTxType block
+ {98347375, ID{Hash: checksumToBytes(0xf2be985d), Next: 98347376}}, // Last EthTxType block
+ {98347376, ID{Hash: checksumToBytes(0xf99f3ae7), Next: 111736800}}, // First Magma block
+ {111736799, ID{Hash: checksumToBytes(0xf99f3ae7), Next: 111736800}}, // Last Magma block
+ {111736800, ID{Hash: checksumToBytes(0x40c759b1), Next: 119145600}}, // First Kore block
+ {119145599, ID{Hash: checksumToBytes(0x40c759b1), Next: 119145600}}, // Last Kore block
+ {119145600, ID{Hash: checksumToBytes(0x989f8b4a), Next: 131608000}}, // First Kip103 block
+ {131607999, ID{Hash: checksumToBytes(0x989f8b4a), Next: 131608000}}, // Last Kip103 block
+ {131608000, ID{Hash: checksumToBytes(0xff2bb36d), Next: 141367000}}, // First Shanghai block
+ {141366999, ID{Hash: checksumToBytes(0xff2bb36d), Next: 141367000}}, // Last Shanghai block
+ {141367000, ID{Hash: checksumToBytes(0x897592ea), Next: 156660000}}, // First Cancun+Randao block
+ {156659999, ID{Hash: checksumToBytes(0x897592ea), Next: 156660000}}, // Last Cancun+Randao block
+ {156660000, ID{Hash: checksumToBytes(0xf00fbab3), Next: 187930000}}, // First Kaia+Kip160 block
+ {187929999, ID{Hash: checksumToBytes(0xf00fbab3), Next: 187930000}}, // Last Kaia+Kip160 block
+ {187930000, ID{Hash: checksumToBytes(0x0d29cd98), Next: 0}}, // First Prague block
+ {198978293, ID{Hash: checksumToBytes(0x0d29cd98), Next: 0}}, // Last Prague block
+ },
+ },
+ }
+ for i, tt := range tests {
+ for j, ttt := range tt.cases {
+ if have := NewID(tt.config, tt.genesis, ttt.head); have != ttt.want {
+ t.Errorf("test %d, case %d: fork ID mismatch: have %x, want %x", i, j, have, ttt.want)
+ }
+ }
+ }
+}
+
+func TestCheckForkCompatibleBlock(t *testing.T) {
+ type expectedNums struct {
+ currentForkCompatibleBlock *big.Int
+ nextForkCompatibleBlock *big.Int
+ lastForkCompatibleBlock *big.Int
+ }
+ type testcase struct {
+ head uint64
+ expectedNums expectedNums
+ }
+ tests := []struct {
+ config *params.ChainConfig
+ cases []testcase
+ }{
+ // Mainnet test cases
+ {
+ params.MainnetChainConfig,
+ []testcase{
+ {0, expectedNums{big.NewInt(0), big.NewInt(86816005), big.NewInt(190670000)}}, // head is Genesis block
+ {86816005, expectedNums{big.NewInt(86816005), big.NewInt(99841497), big.NewInt(190670000)}}, // head is Istanbul+London+EthTxType block
+ {99841497, expectedNums{big.NewInt(99841497), big.NewInt(119750400), big.NewInt(190670000)}}, // head is Magma block
+ {119750400, expectedNums{big.NewInt(119750400), big.NewInt(135456000), big.NewInt(190670000)}}, // head is Kore+Kip103 block
+ {135456000, expectedNums{big.NewInt(135456000), big.NewInt(147534000), big.NewInt(190670000)}}, // head is Shanghai block
+ {147534000, expectedNums{big.NewInt(147534000), big.NewInt(162900480), big.NewInt(190670000)}}, // head is Cancun+Randao block
+ {162900480, expectedNums{big.NewInt(162900480), big.NewInt(190670000), big.NewInt(190670000)}}, // head is Kaia+Kip160 block
+ {190670000, expectedNums{big.NewInt(190670000), nil, big.NewInt(190670000)}}, // head is Prague block
+ },
+ },
+ // Kairos test cases
+ {
+ params.KairosChainConfig,
+ []testcase{
+ {0, expectedNums{big.NewInt(0), big.NewInt(75373312), big.NewInt(187930000)}}, // head is Genesis block
+ {75373312, expectedNums{big.NewInt(75373312), big.NewInt(80295291), big.NewInt(187930000)}}, // head is Istanbul block
+ {80295291, expectedNums{big.NewInt(80295291), big.NewInt(86513895), big.NewInt(187930000)}}, // head is London block
+ {86513895, expectedNums{big.NewInt(86513895), big.NewInt(98347376), big.NewInt(187930000)}}, // head is EthTxType block
+ {98347376, expectedNums{big.NewInt(98347376), big.NewInt(111736800), big.NewInt(187930000)}}, // head is Magma block
+ {111736800, expectedNums{big.NewInt(111736800), big.NewInt(119145600), big.NewInt(187930000)}}, // head is Kore block
+ {119145600, expectedNums{big.NewInt(119145600), big.NewInt(131608000), big.NewInt(187930000)}}, // head is Kip103 block
+ {131608000, expectedNums{big.NewInt(131608000), big.NewInt(141367000), big.NewInt(187930000)}}, // head is Shanghai block
+ {141367000, expectedNums{big.NewInt(141367000), big.NewInt(156660000), big.NewInt(187930000)}}, // head is Cancun+Randao block
+ {156660000, expectedNums{big.NewInt(156660000), big.NewInt(187930000), big.NewInt(187930000)}}, // head is Kaia+Kip160 block
+ {187930000, expectedNums{big.NewInt(187930000), nil, big.NewInt(187930000)}}, // head is Prague block
+ },
+ },
+ }
+ for i, tt := range tests {
+ for j, ttt := range tt.cases {
+ latestForkCompatibleBlock := LatestForkCompatibleBlock(tt.config, new(big.Int).SetUint64(ttt.head))
+ nextForkCompatibleBlock := NextForkCompatibleBlock(tt.config, new(big.Int).SetUint64(ttt.head))
+ lastForkCompatibleBlock := LastForkCompatibleBlock(tt.config)
+ if latestForkCompatibleBlock.Cmp(ttt.expectedNums.currentForkCompatibleBlock) != 0 {
+ t.Errorf("test %d, case %d: latest fork compatible block mismatch: have %x, want %x", i, j, latestForkCompatibleBlock, ttt.expectedNums.currentForkCompatibleBlock)
+ }
+ if nextForkCompatibleBlock == nil {
+ if ttt.expectedNums.nextForkCompatibleBlock != nil {
+ t.Errorf("test %d, case %d: next fork compatible block is nil, but expected %x", i, j, ttt.expectedNums.nextForkCompatibleBlock)
+ }
+ } else if nextForkCompatibleBlock.Cmp(ttt.expectedNums.nextForkCompatibleBlock) != 0 {
+ t.Errorf("test %d, case %d: next fork compatible block mismatch: have %x, want %x", i, j, nextForkCompatibleBlock, ttt.expectedNums.nextForkCompatibleBlock)
+ }
+ if lastForkCompatibleBlock.Cmp(ttt.expectedNums.lastForkCompatibleBlock) != 0 {
+ t.Errorf("test %d, case %d: last fork compatible block mismatch: have %x, want %x", i, j, lastForkCompatibleBlock, ttt.expectedNums.lastForkCompatibleBlock)
+ }
+ }
+ }
+}
diff --git a/blockchain/system/util.go b/blockchain/system/util.go
new file mode 100644
index 000000000..d4a496f33
--- /dev/null
+++ b/blockchain/system/util.go
@@ -0,0 +1,51 @@
+// Copyright 2025 The Kaia Authors
+// This file is part of the Kaia library.
+//
+// The Kaia library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The Kaia library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the Kaia library. If not, see .
+
+package system
+
+import (
+ "math/big"
+
+ "github.com/kaiachain/kaia/common"
+ "github.com/kaiachain/kaia/params"
+)
+
+// ActiveSystemContracts returns the currently active system contracts at the
+// given block number.
+func ActiveSystemContracts(c *params.ChainConfig, genesis common.Hash, head *big.Int) map[string]common.Address {
+ active := make(map[string]common.Address)
+
+ if c.IsPragueForkEnabled(head) {
+ active["HISTORY_STORAGE_ADDRESS"] = params.HistoryStorageAddress
+ }
+ if c.IsKip160ForkEnabled(head) {
+ active["KIP160"] = c.Kip160ContractAddress
+ }
+ if c.IsRandaoForkEnabled(head) {
+ active["REGISTRY"] = RegistryAddr
+ }
+ if c.IsKip103ForkEnabled(head) {
+ active["KIP103"] = c.Kip103ContractAddress
+ }
+
+ // These contracts are active from genesis.
+ if genesis == params.MainnetGenesisHash {
+ active["MAINNET_CREDIT"] = MainnetCreditAddr
+ }
+ active["ADDRESS_BOOK"] = AddressBookAddr
+
+ return active
+}
diff --git a/blockchain/system/util_test.go b/blockchain/system/util_test.go
new file mode 100644
index 000000000..0d1faac0f
--- /dev/null
+++ b/blockchain/system/util_test.go
@@ -0,0 +1,117 @@
+// Copyright 2025 The Kaia Authors
+// This file is part of the Kaia library.
+//
+// The Kaia library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The Kaia library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the Kaia library. If not, see .
+
+package system
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/kaiachain/kaia/common"
+ "github.com/kaiachain/kaia/params"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestActiveSystemContracts(t *testing.T) {
+ mainnetConfig := params.MainnetChainConfig
+ mainnetConfig.Kip160ContractAddress = common.HexToAddress("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+ mainnetConfig.Kip103ContractAddress = common.HexToAddress("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
+
+ cases := []struct {
+ name string
+ head *big.Int
+ chainConfig *params.ChainConfig
+ genesisHash common.Hash
+ expected map[string]common.Address
+ }{
+ {
+ name: "Genesis block - testnet",
+ head: big.NewInt(0),
+ chainConfig: params.KairosChainConfig,
+ genesisHash: params.KairosGenesisHash,
+ expected: map[string]common.Address{
+ "ADDRESS_BOOK": AddressBookAddr,
+ },
+ },
+ {
+ name: "Genesis block - mainnet",
+ head: big.NewInt(0),
+ chainConfig: mainnetConfig,
+ genesisHash: params.MainnetGenesisHash,
+ expected: map[string]common.Address{
+ "MAINNET_CREDIT": MainnetCreditAddr,
+ "ADDRESS_BOOK": AddressBookAddr,
+ },
+ },
+ {
+ name: "Kip103 head - mainnet",
+ head: big.NewInt(119750400),
+ chainConfig: mainnetConfig,
+ genesisHash: params.MainnetGenesisHash,
+ expected: map[string]common.Address{
+ "KIP103": mainnetConfig.Kip103ContractAddress,
+ "MAINNET_CREDIT": MainnetCreditAddr,
+ "ADDRESS_BOOK": AddressBookAddr,
+ },
+ },
+ {
+ name: "Randao head - mainnet",
+ head: big.NewInt(147534000),
+ chainConfig: mainnetConfig,
+ genesisHash: params.MainnetGenesisHash,
+ expected: map[string]common.Address{
+ "REGISTRY": RegistryAddr,
+ "KIP103": mainnetConfig.Kip103ContractAddress,
+ "MAINNET_CREDIT": MainnetCreditAddr,
+ "ADDRESS_BOOK": AddressBookAddr,
+ },
+ },
+ {
+ name: "Kip160 head - mainnet",
+ head: big.NewInt(162900480),
+ chainConfig: mainnetConfig,
+ genesisHash: params.MainnetGenesisHash,
+ expected: map[string]common.Address{
+ "KIP160": mainnetConfig.Kip160ContractAddress,
+ "REGISTRY": RegistryAddr,
+ "KIP103": mainnetConfig.Kip103ContractAddress,
+ "MAINNET_CREDIT": MainnetCreditAddr,
+ "ADDRESS_BOOK": AddressBookAddr,
+ },
+ },
+ {
+ name: "Prague head - mainnet",
+ head: big.NewInt(190670000),
+ chainConfig: mainnetConfig,
+ genesisHash: params.MainnetGenesisHash,
+ expected: map[string]common.Address{
+ "HISTORY_STORAGE_ADDRESS": params.HistoryStorageAddress,
+ "KIP160": mainnetConfig.Kip160ContractAddress,
+ "REGISTRY": RegistryAddr,
+ "KIP103": mainnetConfig.Kip103ContractAddress,
+ "MAINNET_CREDIT": MainnetCreditAddr,
+ "ADDRESS_BOOK": AddressBookAddr,
+ },
+ },
+ }
+
+ for _, tt := range cases {
+ t.Run(tt.name, func(t *testing.T) {
+ actual := ActiveSystemContracts(tt.chainConfig, tt.genesisHash, tt.head)
+ assert.Equal(t, tt.expected, actual)
+ })
+ }
+}
diff --git a/blockchain/vm/contracts.go b/blockchain/vm/contracts.go
index 324921435..782ad74ff 100644
--- a/blockchain/vm/contracts.go
+++ b/blockchain/vm/contracts.go
@@ -75,6 +75,8 @@ type PrecompiledContract interface {
// Run runs the precompiled contract
// contract, evm is only exists in Kaia, those are not used in go-ethereum
Run(input []byte, contract *Contract, evm *EVM) ([]byte, error)
+
+ Name() string
}
// PrecompiledContractsByzantium contains the default set of pre-compiled Kaia
@@ -233,19 +235,9 @@ func init() {
// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
var precompiledContractAddrs []common.Address
- switch {
- case rules.IsOsaka:
- precompiledContractAddrs = PrecompiledAddressOsaka
- case rules.IsPrague:
- precompiledContractAddrs = PrecompiledAddressPrague
- case rules.IsCancun:
- precompiledContractAddrs = PrecompiledAddressCancun
- case rules.IsIstanbul:
- precompiledContractAddrs = PrecompiledAddressIstanbul
- default:
- precompiledContractAddrs = PrecompiledAddressesByzantium
+ for addr := range ActivePrecompiledContracts(rules) {
+ precompiledContractAddrs = append(precompiledContractAddrs, addr)
}
-
// After istanbulCompatible hf, need to support for vmversion0 contracts, too.
// VmVersion0 contracts are deployed before istanbulCompatible and they use byzantiumCompatible precompiled contracts.
// VmVersion0 contracts are the contracts deployed before istanbulCompatible hf.
@@ -257,6 +249,26 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
}
}
+// ActivePrecompiledContracts returns the precompiled contracts enabled with the current configuration.
+// This function doesn't support for vmversion0 contracts, it only supports for istanbulCompatible hf.
+func ActivePrecompiledContracts(rules params.Rules) map[common.Address]PrecompiledContract {
+ var precompiledContracts map[common.Address]PrecompiledContract
+ switch {
+ case rules.IsOsaka:
+ precompiledContracts = PrecompiledContractsOsaka
+ case rules.IsPrague:
+ precompiledContracts = PrecompiledContractsPrague
+ case rules.IsCancun:
+ precompiledContracts = PrecompiledContractsCancun
+ case rules.IsIstanbul:
+ precompiledContracts = PrecompiledContractsIstanbul
+ default:
+ precompiledContracts = PrecompiledContractsByzantium
+ }
+
+ return precompiledContracts
+}
+
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract, evm *EVM) (ret []byte, computationCost uint64, err error) {
gas, computationCost := p.GetRequiredGasAndComputationCost(input)
@@ -305,6 +317,10 @@ func (c *ecrecover) Run(input []byte, contract *Contract, evm *EVM) ([]byte, err
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{}
@@ -325,6 +341,10 @@ func (c *sha256hash) Run(input []byte, contract *Contract, evm *EVM) ([]byte, er
return h[:], nil
}
+func (c *sha256hash) Name() string {
+ return "SHA256"
+}
+
// RIPEMD160 implemented as a native contract.
type ripemd160hash struct{}
@@ -346,6 +366,10 @@ func (c *ripemd160hash) Run(input []byte, contract *Contract, evm *EVM) ([]byte,
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{}
@@ -364,6 +388,10 @@ func (c *dataCopy) Run(in []byte, contract *Contract, evm *EVM) ([]byte, error)
return in, nil
}
+func (c *dataCopy) Name() string {
+ return "ID"
+}
+
// bigModExp implements a native big integer exponential modular operation.
type bigModExp struct {
eip2565 bool
@@ -371,6 +399,10 @@ type bigModExp struct {
eip7883 bool
}
+func (c *bigModExp) Name() string {
+ return "MODEXP"
+}
+
// byzantiumMultComplexity implements the bigModexp multComplexity formula, as defined in EIP-198.
//
// def mult_complexity(x):
@@ -685,6 +717,10 @@ func (c *bn256AddIstanbul) Run(input []byte, contract *Contract, evm *EVM) ([]by
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{}
@@ -697,6 +733,10 @@ func (c *bn256AddByzantium) Run(input []byte, contract *Contract, evm *EVM) ([]b
return runBn256Add(input)
}
+func (c *bn256AddByzantium) Name() string {
+ return "BN254_ADD"
+}
+
// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by
// both Constantionple and Istanbul operations.
func runBn256ScalarMul(input []byte) ([]byte, error) {
@@ -721,6 +761,10 @@ func (c *bn256ScalarMulIstanbul) Run(input []byte, contract *Contract, evm *EVM)
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{}
@@ -733,6 +777,10 @@ func (c *bn256ScalarMulByzantium) Run(input []byte, contract *Contract, evm *EVM
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}
@@ -789,6 +837,10 @@ func (c *bn256PairingIstanbul) Run(input []byte, contract *Contract, evm *EVM) (
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{}
@@ -803,6 +855,10 @@ func (c *bn256PairingByzantium) Run(input []byte, contract *Contract, evm *EVM)
return runBn256Pairing(input)
}
+func (c *bn256PairingByzantium) Name() string {
+ return "BN254_PAIRING"
+}
+
type blake2F struct{}
const (
@@ -865,6 +921,10 @@ func (c *blake2F) Run(input []byte, contract *Contract, evm *EVM) ([]byte, error
return output, nil
}
+func (c *blake2F) Name() string {
+ return "BLAKE2F"
+}
+
// kzgPointEvaluation implements the EIP-4844 point evaluation precompile.
type kzgPointEvaluation struct{}
@@ -921,6 +981,10 @@ func (b *kzgPointEvaluation) Run(input []byte, contract *Contract, evm *EVM) ([]
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[:])
@@ -953,6 +1017,10 @@ func (c *vmLog) Run(input []byte, contract *Contract, evm *EVM) ([]byte, error)
return nil, nil
}
+func (c *vmLog) Name() string {
+ return "VMLOG"
+}
+
type feePayer struct{}
func (c *feePayer) GetRequiredGasAndComputationCost(input []byte) (uint64, uint64) {
@@ -963,6 +1031,10 @@ func (c *feePayer) Run(input []byte, contract *Contract, evm *EVM) ([]byte, erro
return contract.FeePayerAddress.Bytes(), nil
}
+func (c *feePayer) Name() string {
+ return "FEE_PAYER"
+}
+
type validateSender struct{}
func (c *validateSender) GetRequiredGasAndComputationCost(input []byte) (uint64, uint64) {
@@ -981,6 +1053,10 @@ func (c *validateSender) Run(input []byte, contract *Contract, evm *EVM) ([]byte
return []byte{1}, nil
}
+func (c *validateSender) Name() string {
+ return "VALIDATE_SENDER"
+}
+
func (c *validateSender) validateSender(input []byte, picker types.AccountKeyPicker, currentBlockNumber uint64) error {
ptr := input
@@ -1068,6 +1144,10 @@ func (c *bls12381G1Add) Run(input []byte, contract *Contract, evm *EVM) ([]byte,
return encodePointG1(p0), nil
}
+func (c *bls12381G1Add) Name() string {
+ return "BLS12_G1ADD"
+}
+
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
type bls12381G1MultiExp struct{}
@@ -1129,6 +1209,10 @@ func (c *bls12381G1MultiExp) Run(input []byte, contract *Contract, evm *EVM) ([]
return encodePointG1(r), nil
}
+func (c *bls12381G1MultiExp) Name() string {
+ return "BLS12_G1MSM"
+}
+
// bls12381G2Add implements EIP-2537 G2Add precompile.
type bls12381G2Add struct{}
@@ -1166,6 +1250,10 @@ func (c *bls12381G2Add) Run(input []byte, contract *Contract, evm *EVM) ([]byte,
return encodePointG2(r), nil
}
+func (c *bls12381G2Add) Name() string {
+ return "BLS12_G2ADD"
+}
+
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
type bls12381G2MultiExp struct{}
@@ -1227,6 +1315,10 @@ func (c *bls12381G2MultiExp) Run(input []byte, contract *Contract, evm *EVM) ([]
return encodePointG2(r), nil
}
+func (c *bls12381G2MultiExp) Name() string {
+ return "BLS12_G2MSM"
+}
+
// bls12381Pairing implements EIP-2537 Pairing precompile.
type bls12381Pairing struct{}
@@ -1292,6 +1384,10 @@ func (c *bls12381Pairing) Run(input []byte, contract *Contract, evm *EVM) ([]byt
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")
@@ -1410,6 +1506,10 @@ func (c *bls12381MapG1) Run(input []byte, contract *Contract, evm *EVM) ([]byte,
return encodePointG1(&r), nil
}
+func (c *bls12381MapG1) Name() string {
+ return "BLS12_MAP_FP_TO_G1"
+}
+
// bls12381MapG2 implements EIP-2537 MapG2 precompile.
type bls12381MapG2 struct{}
@@ -1443,6 +1543,10 @@ func (c *bls12381MapG2) Run(input []byte, contract *Contract, evm *EVM) ([]byte,
return encodePointG2(&r), nil
}
+func (c *bls12381MapG2) Name() string {
+ return "BLS12_MAP_FP2_TO_G2"
+}
+
// consoleLog implements solidity console.log for local networks.
type consoleLog struct{}
@@ -1458,6 +1562,10 @@ func (c *consoleLog) Run(input []byte, contract *Contract, evm *EVM) ([]byte, er
return nil, nil
}
+func (c *consoleLog) Name() string {
+ return "CONSOLE_LOG"
+}
+
// Hardhat console.log accepts format string, however we don't support it.
// Instead, we just join all the parameters with a space.
func (c *consoleLog) toLogString(input []byte) (string, error) {
@@ -1577,3 +1685,7 @@ func (c *p256Verify) Run(input []byte, contract *Contract, evm *EVM) ([]byte, er
}
return nil, nil
}
+
+func (c *p256Verify) Name() string {
+ return "P256VERIFY"
+}
diff --git a/console/web3ext/web3ext.go b/console/web3ext/web3ext.go
index 0b4bc622d..e7acda563 100644
--- a/console/web3ext/web3ext.go
+++ b/console/web3ext/web3ext.go
@@ -185,6 +185,11 @@ web3._extend({
params: 3,
inputFormatter: [null, web3._extend.formatters.inputBlockNumberFormatter, null]
}),
+ new web3._extend.Method({
+ name: 'config',
+ call: 'eth_config',
+ params: 0,
+ }),
],
properties: [
new web3._extend.Property({
diff --git a/node/cn/api_backend.go b/node/cn/api_backend.go
index c4c4db464..8322b51fd 100644
--- a/node/cn/api_backend.go
+++ b/node/cn/api_backend.go
@@ -33,6 +33,7 @@ import (
"github.com/kaiachain/kaia/blockchain"
"github.com/kaiachain/kaia/blockchain/bloombits"
"github.com/kaiachain/kaia/blockchain/state"
+ "github.com/kaiachain/kaia/blockchain/system"
"github.com/kaiachain/kaia/blockchain/types"
"github.com/kaiachain/kaia/blockchain/vm"
"github.com/kaiachain/kaia/common"
@@ -72,6 +73,10 @@ func (b *CNAPIBackend) GetTxLookupInfoAndReceiptInCache(txHash common.Hash) (*ty
return b.cn.blockchain.GetTxLookupInfoAndReceiptInCache(txHash)
}
+func (b *CNAPIBackend) GetActiveSystemContracts(c *params.ChainConfig, genesis common.Hash, head *big.Int) map[string]common.Address {
+ return system.ActiveSystemContracts(c, genesis, head)
+}
+
func (b *CNAPIBackend) ChainConfig() *params.ChainConfig {
return b.cn.chainConfig
}
diff --git a/params/config.go b/params/config.go
index b82d8cf25..b248351e8 100644
--- a/params/config.go
+++ b/params/config.go
@@ -325,6 +325,13 @@ func (c *IstanbulConfig) String() string {
return "istanbul"
}
+// TODO-Kaia Add BlobConfig
+type BlobConfig struct{}
+
+func (c *ChainConfig) BlobConfig(head uint64) *BlobConfig {
+ return nil
+}
+
// String implements the fmt.Stringer interface.
func (c *ChainConfig) String() string {
var engine interface{}
@@ -428,6 +435,16 @@ func (c *ChainConfig) IsKaiaForkEnabled(num *big.Int) bool {
return isForked(c.KaiaCompatibleBlock, num)
}
+// IsKip103ForkEnabled returns whether num is either equal to the kip103 block or greater.
+func (c *ChainConfig) IsKip103ForkEnabled(num *big.Int) bool {
+ return isForked(c.Kip103CompatibleBlock, num)
+}
+
+// IsKip160ForkEnabled returns whether num is either equal to the kip160 block or greater.
+func (c *ChainConfig) IsKip160ForkEnabled(num *big.Int) bool {
+ return isForked(c.Kip160CompatibleBlock, num)
+}
+
// IsRandaoForkEnabled returns whether num is either equal to the randao block or greater.
func (c *ChainConfig) IsRandaoForkEnabled(num *big.Int) bool {
return isForked(c.RandaoCompatibleBlock, num)