From 7f97e772ec9d32ca14e98299ff8ab93973427068 Mon Sep 17 00:00:00 2001 From: Levi Aul Date: Sat, 2 Jul 2022 10:56:15 -0700 Subject: [PATCH 1/4] Add eth_getBalanceChangesInBlock RPC endpoint --- cmd/rpcdaemon/commands/eth_api_test.go | 14 +++ .../commands/eth_get_balance_changes.go | 97 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 cmd/rpcdaemon/commands/eth_get_balance_changes.go diff --git a/cmd/rpcdaemon/commands/eth_api_test.go b/cmd/rpcdaemon/commands/eth_api_test.go index cc940c43e66..d07ff7da57e 100644 --- a/cmd/rpcdaemon/commands/eth_api_test.go +++ b/cmd/rpcdaemon/commands/eth_api_test.go @@ -16,6 +16,20 @@ import ( "github.com/ledgerwatch/erigon/common" ) +func TestGetBalanceChangesInBlock(t *testing.T) { + var myBlockNum uint64 = 5 + + db := rpcdaemontest.CreateTestKV(t) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(nil, stateCache, snapshotsync.NewBlockReader(), false), db, nil, nil, nil, 5000000) + balances, err := api.GetBalanceChangesInBlock(myBlockNum) + if err != nil { + t.Errorf("calling GetChangeSet resulted in an error: %v", err) + } + PrintChangedBalances(balances) + +} + func TestGetTransactionReceipt(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) diff --git a/cmd/rpcdaemon/commands/eth_get_balance_changes.go b/cmd/rpcdaemon/commands/eth_get_balance_changes.go new file mode 100644 index 00000000000..081bd69787c --- /dev/null +++ b/cmd/rpcdaemon/commands/eth_get_balance_changes.go @@ -0,0 +1,97 @@ +package commands + +import ( + "bytes" + "context" + "fmt" + + "github.com/holiman/uint256" + + "github.com/ledgerwatch/erigon-lib/kv" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/changeset" + "github.com/ledgerwatch/erigon/common/dbutils" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/types/accounts" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" +) + +type oldNewBalance struct { + oldBalance *hexutil.Big + newBalance *hexutil.Big +} + +func (api *APIImpl) GetBalanceChangesInBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address]*hexutil.Big, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + blockNumber, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) + if err != nil { + return nil, err + } + + c, err := tx.Cursor(kv.AccountChangeSet) + if err != nil { + return nil, err + } + defer c.Close() + + startkey := dbutils.EncodeBlockNumber(blockNumber) + + decodeFn := changeset.Mapper[kv.AccountChangeSet].Decode + + balancesMapping := make(map[common.Address]*hexutil.Big) + + newReader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, api.filters, api.stateCache) + if err != nil { + return nil, err + } + + for dbKey, dbValue, _ := c.Seek(startkey); bytes.Equal(dbKey, startkey) && dbKey != nil; dbKey, dbValue, _ = c.Next() { + _, addressBytes, v, err := decodeFn(dbKey, dbValue) + if err != nil { + return nil, err + } + + var oldAcc accounts.Account + if err = oldAcc.DecodeForStorage(v); err != nil { + return nil, err + } + oldBalance := oldAcc.Balance + + address := common.BytesToAddress(addressBytes) + + newAcc, err := newReader.ReadAccountData(address) + if err != nil { + return nil, err + } + + newBalance := uint256.NewInt(0) + if newAcc != nil { + newBalance = &newAcc.Balance + } + + if !oldBalance.Eq(newBalance) { + newBalanceDesc := (*hexutil.Big)(newBalance.ToBig()) + balancesMapping[address] = newBalanceDesc + } + } + + return balancesMapping, nil +} + +func PrintChangedBalances(mapping map[common.Address]oldNewBalance) error { + + for address, balances := range mapping { + fmt.Println("address: ", address) + fmt.Println("old balance: ", balances.oldBalance) + fmt.Println("new balance: ", balances.newBalance) + } + + return nil +} From 8f5398e97af3889d625ab5d13b4e69fd8202f589 Mon Sep 17 00:00:00 2001 From: Levi Aul Date: Sat, 2 Jul 2022 11:43:23 -0700 Subject: [PATCH 2/4] Fix lints --- cmd/rpcdaemon/commands/eth_api_test.go | 6 +++--- cmd/rpcdaemon/commands/eth_get_balance_changes.go | 13 +++---------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/cmd/rpcdaemon/commands/eth_api_test.go b/cmd/rpcdaemon/commands/eth_api_test.go index d07ff7da57e..44ad8552864 100644 --- a/cmd/rpcdaemon/commands/eth_api_test.go +++ b/cmd/rpcdaemon/commands/eth_api_test.go @@ -17,14 +17,14 @@ import ( ) func TestGetBalanceChangesInBlock(t *testing.T) { - var myBlockNum uint64 = 5 + myBlockNum := rpc.BlockNumberOrHashWithNumber(5) db := rpcdaemontest.CreateTestKV(t) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) api := NewEthAPI(NewBaseApi(nil, stateCache, snapshotsync.NewBlockReader(), false), db, nil, nil, nil, 5000000) - balances, err := api.GetBalanceChangesInBlock(myBlockNum) + balances, err := api.GetBalanceChangesInBlock(context.Background(), myBlockNum) if err != nil { - t.Errorf("calling GetChangeSet resulted in an error: %v", err) + t.Errorf("calling GetBalanceChangesInBlock resulted in an error: %v", err) } PrintChangedBalances(balances) diff --git a/cmd/rpcdaemon/commands/eth_get_balance_changes.go b/cmd/rpcdaemon/commands/eth_get_balance_changes.go index 081bd69787c..ef9b052edd3 100644 --- a/cmd/rpcdaemon/commands/eth_get_balance_changes.go +++ b/cmd/rpcdaemon/commands/eth_get_balance_changes.go @@ -18,11 +18,6 @@ import ( "github.com/ledgerwatch/erigon/turbo/rpchelper" ) -type oldNewBalance struct { - oldBalance *hexutil.Big - newBalance *hexutil.Big -} - func (api *APIImpl) GetBalanceChangesInBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address]*hexutil.Big, error) { tx, err := api.db.BeginRo(ctx) if err != nil { @@ -85,12 +80,10 @@ func (api *APIImpl) GetBalanceChangesInBlock(ctx context.Context, blockNrOrHash return balancesMapping, nil } -func PrintChangedBalances(mapping map[common.Address]oldNewBalance) error { - - for address, balances := range mapping { +func PrintChangedBalances(mapping map[common.Address]*hexutil.Big) error { + for address, newBalance := range mapping { fmt.Println("address: ", address) - fmt.Println("old balance: ", balances.oldBalance) - fmt.Println("new balance: ", balances.newBalance) + fmt.Println("new balance: ", newBalance) } return nil From 25be3d63469839f4f79952efae86bf20a093248d Mon Sep 17 00:00:00 2001 From: fatemebagherii Date: Thu, 7 Jul 2022 19:18:04 -0700 Subject: [PATCH 3/4] added assertion for one test --- cmd/rpcdaemon/commands/eth_api_test.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/cmd/rpcdaemon/commands/eth_api_test.go b/cmd/rpcdaemon/commands/eth_api_test.go index 44ad8552864..da0a779854b 100644 --- a/cmd/rpcdaemon/commands/eth_api_test.go +++ b/cmd/rpcdaemon/commands/eth_api_test.go @@ -5,6 +5,8 @@ import ( "fmt" "testing" + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/internal/ethapi" "github.com/ledgerwatch/erigon/rpc" @@ -17,7 +19,8 @@ import ( ) func TestGetBalanceChangesInBlock(t *testing.T) { - myBlockNum := rpc.BlockNumberOrHashWithNumber(5) + assert := assert.New(t) + myBlockNum := rpc.BlockNumberOrHashWithNumber(0) db := rpcdaemontest.CreateTestKV(t) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) @@ -26,8 +29,16 @@ func TestGetBalanceChangesInBlock(t *testing.T) { if err != nil { t.Errorf("calling GetBalanceChangesInBlock resulted in an error: %v", err) } - PrintChangedBalances(balances) - + expected := map[common.Address]*hexutil.Big{ + common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"): (*hexutil.Big)(uint256.NewInt(200000000000000000).ToBig()), + common.HexToAddress("0x703c4b2bD70c169f5717101CaeE543299Fc946C7"): (*hexutil.Big)(uint256.NewInt(300000000000000000).ToBig()), + common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): (*hexutil.Big)(uint256.NewInt(9000000000000000000).ToBig()), + } + assert.Equal(len(expected), len(balances)) + for i := range balances { + assert.Contains(expected, i, "%s is not expected to be present in the output.", i) + assert.Equal(balances[i], expected[i], "the value for %s is expected to be %v, but got %v.", i, expected[i], balances[i]) + } } func TestGetTransactionReceipt(t *testing.T) { From aa2d27f3acdc156f1d45c37a03410ef201e6ad4b Mon Sep 17 00:00:00 2001 From: fatemebagherii Date: Mon, 11 Jul 2022 15:14:41 -0700 Subject: [PATCH 4/4] moved balance change api from eth to erigon --- cmd/rpcdaemon/commands/erigon_api.go | 2 + cmd/rpcdaemon/commands/erigon_block.go | 68 ++++++++++++++ cmd/rpcdaemon/commands/eth_api_test.go | 2 +- .../commands/eth_get_balance_changes.go | 90 ------------------- 4 files changed, 71 insertions(+), 91 deletions(-) delete mode 100644 cmd/rpcdaemon/commands/eth_get_balance_changes.go diff --git a/cmd/rpcdaemon/commands/erigon_api.go b/cmd/rpcdaemon/commands/erigon_api.go index f976cf31f05..87781938642 100644 --- a/cmd/rpcdaemon/commands/erigon_api.go +++ b/cmd/rpcdaemon/commands/erigon_api.go @@ -5,6 +5,7 @@ import ( "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/p2p" "github.com/ledgerwatch/erigon/rpc" @@ -20,6 +21,7 @@ type ErigonAPI interface { GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) GetHeaderByHash(_ context.Context, hash common.Hash) (*types.Header, error) GetBlockByTimestamp(ctx context.Context, timeStamp rpc.Timestamp, fullTx bool) (map[string]interface{}, error) + GetBalanceChangesInBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address]*hexutil.Big, error) // Receipt related (see ./erigon_receipts.go) GetLogsByHash(ctx context.Context, hash common.Hash) ([][]*types.Log, error) diff --git a/cmd/rpcdaemon/commands/erigon_block.go b/cmd/rpcdaemon/commands/erigon_block.go index 7a5bf1bda1d..e56cba2a1d3 100644 --- a/cmd/rpcdaemon/commands/erigon_block.go +++ b/cmd/rpcdaemon/commands/erigon_block.go @@ -1,15 +1,21 @@ package commands import ( + "bytes" "context" "errors" "fmt" "sort" + "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/changeset" + "github.com/ledgerwatch/erigon/common/dbutils" + "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/types/accounts" "github.com/ledgerwatch/erigon/internal/ethapi" "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/turbo/rpchelper" @@ -168,3 +174,65 @@ func buildBlockResponse(db kv.Tx, blockNum uint64, fullTx bool) (map[string]inte } return response, err } + +func (api *ErigonImpl) GetBalanceChangesInBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address]*hexutil.Big, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + blockNumber, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) + if err != nil { + return nil, err + } + + c, err := tx.Cursor(kv.AccountChangeSet) + if err != nil { + return nil, err + } + defer c.Close() + + startkey := dbutils.EncodeBlockNumber(blockNumber) + + decodeFn := changeset.Mapper[kv.AccountChangeSet].Decode + + balancesMapping := make(map[common.Address]*hexutil.Big) + + newReader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, api.filters, api.stateCache) + if err != nil { + return nil, err + } + + for dbKey, dbValue, _ := c.Seek(startkey); bytes.Equal(dbKey, startkey) && dbKey != nil; dbKey, dbValue, _ = c.Next() { + _, addressBytes, v, err := decodeFn(dbKey, dbValue) + if err != nil { + return nil, err + } + + var oldAcc accounts.Account + if err = oldAcc.DecodeForStorage(v); err != nil { + return nil, err + } + oldBalance := oldAcc.Balance + + address := common.BytesToAddress(addressBytes) + + newAcc, err := newReader.ReadAccountData(address) + if err != nil { + return nil, err + } + + newBalance := uint256.NewInt(0) + if newAcc != nil { + newBalance = &newAcc.Balance + } + + if !oldBalance.Eq(newBalance) { + newBalanceDesc := (*hexutil.Big)(newBalance.ToBig()) + balancesMapping[address] = newBalanceDesc + } + } + + return balancesMapping, nil +} diff --git a/cmd/rpcdaemon/commands/eth_api_test.go b/cmd/rpcdaemon/commands/eth_api_test.go index da0a779854b..043f620db7b 100644 --- a/cmd/rpcdaemon/commands/eth_api_test.go +++ b/cmd/rpcdaemon/commands/eth_api_test.go @@ -24,7 +24,7 @@ func TestGetBalanceChangesInBlock(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, snapshotsync.NewBlockReader(), false), db, nil, nil, nil, 5000000) + api := NewErigonAPI(NewBaseApi(nil, stateCache, snapshotsync.NewBlockReader(), false), db, nil) balances, err := api.GetBalanceChangesInBlock(context.Background(), myBlockNum) if err != nil { t.Errorf("calling GetBalanceChangesInBlock resulted in an error: %v", err) diff --git a/cmd/rpcdaemon/commands/eth_get_balance_changes.go b/cmd/rpcdaemon/commands/eth_get_balance_changes.go deleted file mode 100644 index ef9b052edd3..00000000000 --- a/cmd/rpcdaemon/commands/eth_get_balance_changes.go +++ /dev/null @@ -1,90 +0,0 @@ -package commands - -import ( - "bytes" - "context" - "fmt" - - "github.com/holiman/uint256" - - "github.com/ledgerwatch/erigon-lib/kv" - - "github.com/ledgerwatch/erigon/common" - "github.com/ledgerwatch/erigon/common/changeset" - "github.com/ledgerwatch/erigon/common/dbutils" - "github.com/ledgerwatch/erigon/common/hexutil" - "github.com/ledgerwatch/erigon/core/types/accounts" - "github.com/ledgerwatch/erigon/rpc" - "github.com/ledgerwatch/erigon/turbo/rpchelper" -) - -func (api *APIImpl) GetBalanceChangesInBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address]*hexutil.Big, error) { - tx, err := api.db.BeginRo(ctx) - if err != nil { - return nil, err - } - defer tx.Rollback() - - blockNumber, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) - if err != nil { - return nil, err - } - - c, err := tx.Cursor(kv.AccountChangeSet) - if err != nil { - return nil, err - } - defer c.Close() - - startkey := dbutils.EncodeBlockNumber(blockNumber) - - decodeFn := changeset.Mapper[kv.AccountChangeSet].Decode - - balancesMapping := make(map[common.Address]*hexutil.Big) - - newReader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, api.filters, api.stateCache) - if err != nil { - return nil, err - } - - for dbKey, dbValue, _ := c.Seek(startkey); bytes.Equal(dbKey, startkey) && dbKey != nil; dbKey, dbValue, _ = c.Next() { - _, addressBytes, v, err := decodeFn(dbKey, dbValue) - if err != nil { - return nil, err - } - - var oldAcc accounts.Account - if err = oldAcc.DecodeForStorage(v); err != nil { - return nil, err - } - oldBalance := oldAcc.Balance - - address := common.BytesToAddress(addressBytes) - - newAcc, err := newReader.ReadAccountData(address) - if err != nil { - return nil, err - } - - newBalance := uint256.NewInt(0) - if newAcc != nil { - newBalance = &newAcc.Balance - } - - if !oldBalance.Eq(newBalance) { - newBalanceDesc := (*hexutil.Big)(newBalance.ToBig()) - balancesMapping[address] = newBalanceDesc - } - } - - return balancesMapping, nil -} - -func PrintChangedBalances(mapping map[common.Address]*hexutil.Big) error { - for address, newBalance := range mapping { - fmt.Println("address: ", address) - fmt.Println("new balance: ", newBalance) - } - - return nil -}