From 8465b700f770d29089203aa748fce9dad1b659e0 Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Tue, 14 May 2024 14:01:06 +0200 Subject: [PATCH 1/5] Implement QueryBalanceDetails RPC method --- rpc/client.go | 2 + rpc/request.go | 17 ++++++++ rpc/response.go | 15 +++++++ rpc/rpc_client.go | 5 +++ tests/rpc/integration/rpc_client_test.go | 54 ++++++++++++++++++++++++ types/block.go | 21 +++++++++ 6 files changed, 114 insertions(+) diff --git a/rpc/client.go b/rpc/client.go index d3ca8ce..2f242d7 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -119,6 +119,8 @@ type ClientInformational interface { GetPeers(ctx context.Context) (InfoGetPeerResult, error) // QueryBalance queries for balances under a given PurseIdentifier QueryBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) + // QueryBalanceDetails query for full balance information using a purse identifier and a state identifier + QueryBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier, stateIdentifier BalanceStateIdentifier) (QueryBalanceDetailsResult, error) // GetChainspec returns the raw bytes of the chainspec.toml, accounts.toml and global_state.toml files as read at node startup. GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) } diff --git a/rpc/request.go b/rpc/request.go index 32b7045..4234545 100644 --- a/rpc/request.go +++ b/rpc/request.go @@ -48,6 +48,7 @@ const ( MethodPutDeploy Method = "account_put_deploy" MethodSpeculativeExec Method = "speculative_exec" MethodQueryBalance Method = "query_balance" + MethodQueryBalanceDetails Method = "query_balance_details" MethodInfoGetChainspec Method = "info_get_chainspec" ) @@ -111,6 +112,16 @@ type BlockIdentifier struct { Height *uint64 `json:"Height,omitempty"` } +type StateRootInfo struct { + StateRootHash string `json:"state_root_hash"` + Timestamp string `json:"timestamp"` +} + +type BalanceStateIdentifier struct { + Block *BlockIdentifier `json:"block,omitempty"` + StateRoot *StateRootInfo `json:"state_root,omitempty"` +} + type ParamBlockIdentifier struct { BlockIdentifier *BlockIdentifier `json:"block_identifier"` } @@ -155,9 +166,15 @@ type SpeculativeExecParams struct { type PurseIdentifier struct { MainPurseUnderPublicKey *keypair.PublicKey `json:"main_purse_under_public_key,omitempty"` MainPurseUnderAccountHash *string `json:"main_purse_under_account_hash,omitempty"` + MainPurseUnderEntityAddr *string `json:"main_purse_under_entity_addr,omitempty"` PurseUref *string `json:"purse_uref,omitempty"` } type QueryBalanceRequest struct { PurseIdentifier PurseIdentifier `json:"purse_identifier"` } + +type QueryBalanceDetailsRequest struct { + PurseIdentifier PurseIdentifier `json:"purse_identifier"` + StateIdentifier BalanceStateIdentifier `json:"state_identifier"` +} diff --git a/rpc/response.go b/rpc/response.go index d1a3a8b..75268b5 100644 --- a/rpc/response.go +++ b/rpc/response.go @@ -189,6 +189,21 @@ type QueryBalanceResult struct { Balance clvalue.UInt512 `json:"balance"` } +type QueryBalanceDetailsResult struct { + APIVersion string `json:"api_version"` + TotalBalance clvalue.UInt512 `json:"total_balance"` + AvailableBalance clvalue.UInt512 `json:"available_balance"` + TotalBalanceProof string `json:"total_balance_proof"` + Holds []BalanceHoldWithProof `json:"holds"` +} + +// BalanceHoldWithProof The block time at which the hold was created. +type BalanceHoldWithProof struct { + Time types.BlockTime `json:"time"` + Amount clvalue.UInt512 `json:"amount"` + Proof string `json:"proof"` +} + type InfoGetChainspecResult struct { ApiVersion string `json:"api_version"` ChainspecBytes struct { diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 3074804..68a3d29 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -264,6 +264,11 @@ func (c *client) QueryBalance(ctx context.Context, identifier PurseIdentifier) ( return result, c.processRequest(ctx, MethodQueryBalance, QueryBalanceRequest{identifier}, &result) } +func (c *client) QueryBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier, stateIdentifier BalanceStateIdentifier) (QueryBalanceDetailsResult, error) { + var result QueryBalanceDetailsResult + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, stateIdentifier}, &result) +} + func (c *client) GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) { var result InfoGetChainspecResult return result, c.processRequest(ctx, MethodInfoGetChainspec, nil, &result) diff --git a/tests/rpc/integration/rpc_client_test.go b/tests/rpc/integration/rpc_client_test.go index d1bb480..cb88a7e 100644 --- a/tests/rpc/integration/rpc_client_test.go +++ b/tests/rpc/integration/rpc_client_test.go @@ -40,6 +40,60 @@ func Test_DefaultClient_GetAccountInfo_ByAccountKey(t *testing.T) { assert.Equal(t, "account-hash-bf06bdb1616050cea5862333d1f4787718f1011c95574ba92378419eefeeee59", res.Account.AccountHash.ToPrefixedString()) } +func Test_DefaultClient_QueryBalanceDetails(t *testing.T) { + pubKey, err := casper.NewPublicKey("0111bc2070a9af0f26f94b8549bffa5643ead0bc68eba3b1833039cfa2a9a8205d") + require.NoError(t, err) + + ctx := context.Background() + + tests := []struct { + name string + identifier rpc.BalanceStateIdentifier + }{ + { + name: "ByBlock", + identifier: rpc.BalanceStateIdentifier{ + Block: &rpc.BlockIdentifier{ + Height: &[]uint64{165520}[0], + }, + }, + }, + { + name: "ByBlockHash", + identifier: rpc.BalanceStateIdentifier{ + Block: &rpc.BlockIdentifier{ + Hash: &[]string{"ba48f6c4211a98ec0db3e62e95133a5b3cbd521107112cc115ed0ad84bd1083f"}[0], + }, + }, + }, + { + name: "ByStateRoot", + identifier: rpc.BalanceStateIdentifier{ + StateRoot: &rpc.StateRootInfo{ + StateRootHash: "281da1208effdfe4df196ddb83b862e4d11c5f58ddb1de4bfca4f8d43a51b6b4", + Timestamp: "2024-05-14T11:39:50.921Z", + }, + }, + }, + } + + entityAddr := "entity-account-" + pubKey.AccountHash().ToHex() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := GetRpcClient().QueryBalanceDetails(ctx, + rpc.PurseIdentifier{ + MainPurseUnderEntityAddr: &entityAddr, + }, + tt.identifier, + ) + require.NoError(t, err) + assert.NotEmpty(t, result.AvailableBalance) + assert.NotEmpty(t, result.TotalBalance) + assert.NotEmpty(t, result.TotalBalanceProof) + assert.Empty(t, result.Holds) + }) + } +} func Test_DefaultClient_QueryStateByStateHash(t *testing.T) { accountKey := "account-hash-bf06bdb1616050cea5862333d1f4787718f1011c95574ba92378419eefeeee59" res, err := GetRpcClient().QueryGlobalStateByStateHash(context.Background(), nil, accountKey, nil) diff --git a/types/block.go b/types/block.go index 01e0510..1fa1880 100644 --- a/types/block.go +++ b/types/block.go @@ -1,10 +1,31 @@ package types import ( + "encoding/json" "github.com/make-software/casper-go-sdk/types/key" "github.com/make-software/casper-go-sdk/types/keypair" + "time" ) +// BlockTime A newtype wrapping a [`u64`] which represents the block time +type BlockTime struct { + time.Time +} + +func (v BlockTime) MarshalJSON() ([]byte, error) { + return json.Marshal(v.Unix()) +} + +func (v *BlockTime) UnmarshalJSON(data []byte) error { + var blockTime uint64 + if err := json.Unmarshal(data, &blockTime); err != nil { + return err + } + + v.Time = time.Unix(int64(blockTime), 0) + return nil +} + // Block in the network type Block struct { Hash key.Hash `json:"hash"` From c4fa22985ac35eb450aee36b3f4d9eb7931b17dc Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Thu, 23 May 2024 10:26:41 +0200 Subject: [PATCH 2/5] Refactor after review --- rpc/client.go | 6 ++++++ rpc/rpc_client.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/rpc/client.go b/rpc/client.go index 2f242d7..a16aa2e 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -121,6 +121,12 @@ type ClientInformational interface { QueryBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) // QueryBalanceDetails query for full balance information using a purse identifier and a state identifier QueryBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier, stateIdentifier BalanceStateIdentifier) (QueryBalanceDetailsResult, error) + // QueryBalanceDetailsByBlockHeight query for full balance information using a purse identifier and block height + QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) + // QueryBalanceDetailsByBlockHash query for full balance information using a purse identifier and block hash + QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) + // QueryBalanceDetailsByStateRoot query for full balance information using a purse identifier and state root info + QueryBalanceDetailsByStateRoot(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash, timestamp string) (QueryBalanceDetailsResult, error) // GetChainspec returns the raw bytes of the chainspec.toml, accounts.toml and global_state.toml files as read at node startup. GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) } diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 68a3d29..74f8719 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -269,6 +269,34 @@ func (c *client) QueryBalanceDetails(ctx context.Context, purseIdentifier PurseI return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, stateIdentifier}, &result) } +func (c *client) QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) { + var result QueryBalanceDetailsResult + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, BalanceStateIdentifier{ + Block: &BlockIdentifier{ + Height: &height, + }, + }}, &result) +} + +func (c *client) QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) { + var result QueryBalanceDetailsResult + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, BalanceStateIdentifier{ + Block: &BlockIdentifier{ + Hash: &blockHash, + }, + }}, &result) +} + +func (c *client) QueryBalanceDetailsByStateRoot(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash, timestamp string) (QueryBalanceDetailsResult, error) { + var result QueryBalanceDetailsResult + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, BalanceStateIdentifier{ + StateRoot: &StateRootInfo{ + StateRootHash: stateRootHash, + Timestamp: timestamp, + }, + }}, &result) +} + func (c *client) GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) { var result InfoGetChainspecResult return result, c.processRequest(ctx, MethodInfoGetChainspec, nil, &result) From 296114a4ebcfecb25aab99c15b1e4317eda618df Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 29 May 2024 11:48:42 +0300 Subject: [PATCH 3/5] Updated QueryBalanceDetails method signature --- rpc/client.go | 4 ++-- rpc/request.go | 4 ++-- rpc/rpc_client.go | 15 +++++---------- tests/rpc/integration/rpc_client_test.go | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index a16aa2e..075327a 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -125,8 +125,8 @@ type ClientInformational interface { QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) // QueryBalanceDetailsByBlockHash query for full balance information using a purse identifier and block hash QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) - // QueryBalanceDetailsByStateRoot query for full balance information using a purse identifier and state root info - QueryBalanceDetailsByStateRoot(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash, timestamp string) (QueryBalanceDetailsResult, error) + // QueryBalanceDetailsLatest query for latest full balance information using a purse identifier + QueryBalanceDetailsLatest(ctx context.Context, purseIdentifier PurseIdentifier) (QueryBalanceDetailsResult, error) // GetChainspec returns the raw bytes of the chainspec.toml, accounts.toml and global_state.toml files as read at node startup. GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) } diff --git a/rpc/request.go b/rpc/request.go index 4234545..37a2869 100644 --- a/rpc/request.go +++ b/rpc/request.go @@ -175,6 +175,6 @@ type QueryBalanceRequest struct { } type QueryBalanceDetailsRequest struct { - PurseIdentifier PurseIdentifier `json:"purse_identifier"` - StateIdentifier BalanceStateIdentifier `json:"state_identifier"` + PurseIdentifier PurseIdentifier `json:"purse_identifier"` + StateIdentifier *BalanceStateIdentifier `json:"state_identifier,omitempty"` } diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 74f8719..8554080 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -266,12 +266,12 @@ func (c *client) QueryBalance(ctx context.Context, identifier PurseIdentifier) ( func (c *client) QueryBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier, stateIdentifier BalanceStateIdentifier) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, stateIdentifier}, &result) + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &stateIdentifier}, &result) } func (c *client) QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, BalanceStateIdentifier{ + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &BalanceStateIdentifier{ Block: &BlockIdentifier{ Height: &height, }, @@ -280,21 +280,16 @@ func (c *client) QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIden func (c *client) QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, BalanceStateIdentifier{ + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &BalanceStateIdentifier{ Block: &BlockIdentifier{ Hash: &blockHash, }, }}, &result) } -func (c *client) QueryBalanceDetailsByStateRoot(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash, timestamp string) (QueryBalanceDetailsResult, error) { +func (c *client) QueryBalanceDetailsLatest(ctx context.Context, purseIdentifier PurseIdentifier) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, BalanceStateIdentifier{ - StateRoot: &StateRootInfo{ - StateRootHash: stateRootHash, - Timestamp: timestamp, - }, - }}, &result) + return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{PurseIdentifier: purseIdentifier}, &result) } func (c *client) GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) { diff --git a/tests/rpc/integration/rpc_client_test.go b/tests/rpc/integration/rpc_client_test.go index cb88a7e..29c4ed5 100644 --- a/tests/rpc/integration/rpc_client_test.go +++ b/tests/rpc/integration/rpc_client_test.go @@ -94,6 +94,25 @@ func Test_DefaultClient_QueryBalanceDetails(t *testing.T) { }) } } + +func Test_DefaultClient_QueryBalanceDetailsLatest(t *testing.T) { + pubKey, err := casper.NewPublicKey("0111bc2070a9af0f26f94b8549bffa5643ead0bc68eba3b1833039cfa2a9a8205d") + require.NoError(t, err) + + entityAddr := "entity-account-" + pubKey.AccountHash().ToHex() + t.Run("QueryBalanceDetailsLatest", func(t *testing.T) { + result, err := GetRpcClient().QueryBalanceDetailsLatest(context.Background(), + rpc.PurseIdentifier{ + MainPurseUnderEntityAddr: &entityAddr, + }, + ) + require.NoError(t, err) + assert.NotEmpty(t, result.AvailableBalance) + assert.NotEmpty(t, result.TotalBalance) + assert.NotEmpty(t, result.TotalBalanceProof) + }) +} + func Test_DefaultClient_QueryStateByStateHash(t *testing.T) { accountKey := "account-hash-bf06bdb1616050cea5862333d1f4787718f1011c95574ba92378419eefeeee59" res, err := GetRpcClient().QueryGlobalStateByStateHash(context.Background(), nil, accountKey, nil) From 0dbb6167153bab7715dcfeac1f51080e69b96a48 Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 3 Jul 2024 10:48:55 +0200 Subject: [PATCH 4/5] Adjust query_balance and query_balance_details RPC method interfaces --- rpc/client.go | 25 ++++-- rpc/request.go | 49 +++++++---- rpc/response.go | 8 +- rpc/rpc_client.go | 102 +++++++++++++++++++---- tests/rpc/integration/rpc_client_test.go | 88 +++++++------------ tests/rpc/rpc_client_test.go | 10 +-- types/key/account.go | 2 +- types/key/balance_hold_addr.go | 2 +- types/key/bid_addr.go | 2 +- types/key/block_global_addr.go | 2 +- types/key/byte_code.go | 2 +- types/key/contract.go | 2 +- types/key/contract_package.go | 2 +- types/key/entity_addr.go | 2 +- types/key/entry_point_addr.go | 2 +- types/key/hash.go | 2 +- types/key/message_addr.go | 2 +- types/key/named_key_addr.go | 2 +- types/key/transfer.go | 2 +- types/key/uref.go | 3 +- types/keypair/public_key.go | 3 +- 21 files changed, 194 insertions(+), 120 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index 075327a..67be5ce 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -45,10 +45,10 @@ type ClientPOS interface { // The response should be identical, regardless of the node queried, // as the information in question is objective and common to all nodes within a network. type ClientInformational interface { - // GetAccountBalance returns a purse's balance from a network. + // GetBalance returns a purse's balance from a network. // The request takes in the formatted representation of a purse URef as a parameter. // If the param stateRootHash is nil, the client will make an additional RPC call to retrieve the latest stateRootHash. - GetAccountBalance(ctx context.Context, stateRootHash *string, purseURef string) (StateGetBalanceResult, error) + GetBalance(ctx context.Context, purseURef string, stateRootHash *string) (StateGetBalanceResult, error) // GetDeploy retrieves a Deploy from a network. It requires a deploy_hash to query the Deploy. GetDeploy(ctx context.Context, hash string) (InfoGetDeployResult, error) // GetDeployFinalizedApproval returns Deploy with the finalized approvals substituted. @@ -117,16 +117,25 @@ type ClientInformational interface { // GetPeers return a list of peers connected to the node on a Casper network. // The responses return information specific to the queried node, and as such, will vary. GetPeers(ctx context.Context) (InfoGetPeerResult, error) - // QueryBalance queries for balances under a given PurseIdentifier - QueryBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) - // QueryBalanceDetails query for full balance information using a purse identifier and a state identifier - QueryBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier, stateIdentifier BalanceStateIdentifier) (QueryBalanceDetailsResult, error) + + // QueryLatestBalance queries for balances under a given PurseIdentifier + QueryLatestBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) + // QueryBalanceByBlockHeight query for balance information using a purse identifier and block height + QueryBalanceByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceResult, error) + // QueryBalanceByBlockHash query for balance information using a purse identifier and block hash + QueryBalanceByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceResult, error) + // QueryBalanceByStateRootHash query for full balance information using a purse identifier and state root hash + QueryBalanceByStateRootHash(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash string) (QueryBalanceResult, error) + + // QueryLatestBalanceDetails query for full balance information using a purse identifier + QueryLatestBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier) (QueryBalanceDetailsResult, error) // QueryBalanceDetailsByBlockHeight query for full balance information using a purse identifier and block height QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) // QueryBalanceDetailsByBlockHash query for full balance information using a purse identifier and block hash QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) - // QueryBalanceDetailsLatest query for latest full balance information using a purse identifier - QueryBalanceDetailsLatest(ctx context.Context, purseIdentifier PurseIdentifier) (QueryBalanceDetailsResult, error) + // QueryBalanceDetailsByStateRootHash query for full balance information using a purse identifier and state root hash + QueryBalanceDetailsByStateRootHash(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash string) (QueryBalanceDetailsResult, error) + // GetChainspec returns the raw bytes of the chainspec.toml, accounts.toml and global_state.toml files as read at node startup. GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) } diff --git a/rpc/request.go b/rpc/request.go index 37a2869..90303a6 100644 --- a/rpc/request.go +++ b/rpc/request.go @@ -112,14 +112,10 @@ type BlockIdentifier struct { Height *uint64 `json:"Height,omitempty"` } -type StateRootInfo struct { - StateRootHash string `json:"state_root_hash"` - Timestamp string `json:"timestamp"` -} - -type BalanceStateIdentifier struct { - Block *BlockIdentifier `json:"block,omitempty"` - StateRoot *StateRootInfo `json:"state_root,omitempty"` +type GlobalStateIdentifier struct { + BlockHash *string `json:"BlockHash,omitempty"` + BlockHeight *uint64 `json:"BlockHeight,omitempty"` + StateRoot *string `json:"StateRootHash,omitempty"` } type ParamBlockIdentifier struct { @@ -165,16 +161,41 @@ type SpeculativeExecParams struct { type PurseIdentifier struct { MainPurseUnderPublicKey *keypair.PublicKey `json:"main_purse_under_public_key,omitempty"` - MainPurseUnderAccountHash *string `json:"main_purse_under_account_hash,omitempty"` - MainPurseUnderEntityAddr *string `json:"main_purse_under_entity_addr,omitempty"` - PurseUref *string `json:"purse_uref,omitempty"` + MainPurseUnderAccountHash *key.AccountHash `json:"main_purse_under_account_hash,omitempty"` + MainPurseUnderEntityAddr *key.EntityAddr `json:"main_purse_under_entity_addr,omitempty"` + PurseUref *key.URef `json:"purse_uref,omitempty"` +} + +func NewPurseIdentifierFromPublicKey(pubKey keypair.PublicKey) PurseIdentifier { + return PurseIdentifier{ + MainPurseUnderPublicKey: &pubKey, + } +} + +func NewPurseIdentifierFromAccountHash(accountHash key.AccountHash) PurseIdentifier { + return PurseIdentifier{ + MainPurseUnderAccountHash: &accountHash, + } +} + +func NewPurseIdentifierFromEntityAddr(entityAddr key.EntityAddr) PurseIdentifier { + return PurseIdentifier{ + MainPurseUnderEntityAddr: &entityAddr, + } +} + +func NewPurseIdentifierFromUref(uref key.URef) PurseIdentifier { + return PurseIdentifier{ + PurseUref: &uref, + } } type QueryBalanceRequest struct { - PurseIdentifier PurseIdentifier `json:"purse_identifier"` + PurseIdentifier PurseIdentifier `json:"purse_identifier"` + StateIdentifier *GlobalStateIdentifier `json:"state_identifier,omitempty"` } type QueryBalanceDetailsRequest struct { - PurseIdentifier PurseIdentifier `json:"purse_identifier"` - StateIdentifier *BalanceStateIdentifier `json:"state_identifier,omitempty"` + PurseIdentifier PurseIdentifier `json:"purse_identifier"` + StateIdentifier *GlobalStateIdentifier `json:"state_identifier,omitempty"` } diff --git a/rpc/response.go b/rpc/response.go index b49766e..11e8d0f 100644 --- a/rpc/response.go +++ b/rpc/response.go @@ -343,11 +343,17 @@ type QueryBalanceDetailsResult struct { AvailableBalance clvalue.UInt512 `json:"available_balance"` TotalBalanceProof string `json:"total_balance_proof"` Holds []BalanceHoldWithProof `json:"holds"` + + rawJSON json.RawMessage +} + +func (b QueryBalanceDetailsResult) GetRawJSON() json.RawMessage { + return b.rawJSON } // BalanceHoldWithProof The block time at which the hold was created. type BalanceHoldWithProof struct { - Time types.BlockTime `json:"time"` + //Time types.BlockTime `json:"time"` Amount clvalue.UInt512 `json:"amount"` Proof string `json:"proof"` } diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 1167dd4..6981a2f 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -204,7 +204,7 @@ func (c *client) GetDictionaryItemByIdentifier(ctx context.Context, stateRootHas return result, nil } -func (c *client) GetAccountBalance(ctx context.Context, stateRootHash *string, purseURef string) (StateGetBalanceResult, error) { +func (c *client) GetBalance(ctx context.Context, purseURef string, stateRootHash *string) (StateGetBalanceResult, error) { if stateRootHash == nil { latestHashResult, err := c.GetStateRootHashLatest(ctx) if err != nil { @@ -502,10 +502,10 @@ func (c *client) PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployR return result, nil } -func (c *client) QueryBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) { +func (c *client) QueryLatestBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) { var result QueryBalanceResult - resp, err := c.processRequest(ctx, MethodQueryBalance, QueryBalanceRequest{identifier}, &result) + resp, err := c.processRequest(ctx, MethodQueryBalance, QueryBalanceRequest{PurseIdentifier: identifier}, &result) if err != nil { return QueryBalanceResult{}, err } @@ -514,32 +514,100 @@ func (c *client) QueryBalance(ctx context.Context, identifier PurseIdentifier) ( return result, nil } -func (c *client) QueryBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier, stateIdentifier BalanceStateIdentifier) (QueryBalanceDetailsResult, error) { +func (c *client) QueryBalanceByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceResult, error) { + var result QueryBalanceResult + + resp, err := c.processRequest(ctx, MethodQueryBalance, QueryBalanceRequest{PurseIdentifier: purseIdentifier, StateIdentifier: &GlobalStateIdentifier{ + BlockHeight: &height, + }}, &result) + if err != nil { + return QueryBalanceResult{}, err + } + + result.rawJSON = resp.Result + return result, nil +} + +func (c *client) QueryBalanceByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceResult, error) { + var result QueryBalanceResult + + resp, err := c.processRequest(ctx, MethodQueryBalance, QueryBalanceRequest{PurseIdentifier: purseIdentifier, StateIdentifier: &GlobalStateIdentifier{ + BlockHash: &blockHash, + }}, &result) + if err != nil { + return QueryBalanceResult{}, err + } + + result.rawJSON = resp.Result + return result, nil +} + +func (c *client) QueryBalanceByStateRootHash(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash string) (QueryBalanceResult, error) { + var result QueryBalanceResult + + resp, err := c.processRequest(ctx, MethodQueryBalance, QueryBalanceRequest{PurseIdentifier: purseIdentifier, StateIdentifier: &GlobalStateIdentifier{ + StateRoot: &stateRootHash, + }}, &result) + if err != nil { + return QueryBalanceResult{}, err + } + + result.rawJSON = resp.Result + return result, nil +} + +func (c *client) QueryLatestBalanceDetails(ctx context.Context, purseIdentifier PurseIdentifier) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &stateIdentifier}, &result) + + resp, err := c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{PurseIdentifier: purseIdentifier}, &result) + if err != nil { + return QueryBalanceDetailsResult{}, err + } + + result.rawJSON = resp.Result + return result, nil } -func (c *client) QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) { +func (c *client) QueryBalanceDetailsByStateRootHash(ctx context.Context, purseIdentifier PurseIdentifier, stateRootHash string) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &BalanceStateIdentifier{ - Block: &BlockIdentifier{ - Height: &height, - }, + + resp, err := c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &GlobalStateIdentifier{ + StateRoot: &stateRootHash, }}, &result) + if err != nil { + return QueryBalanceDetailsResult{}, err + } + + result.rawJSON = resp.Result + return result, nil } -func (c *client) QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) { +func (c *client) QueryBalanceDetailsByBlockHeight(ctx context.Context, purseIdentifier PurseIdentifier, height uint64) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &BalanceStateIdentifier{ - Block: &BlockIdentifier{ - Hash: &blockHash, - }, + + resp, err := c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &GlobalStateIdentifier{ + BlockHeight: &height, }}, &result) + if err != nil { + return QueryBalanceDetailsResult{}, err + } + + result.rawJSON = resp.Result + return result, nil } -func (c *client) QueryBalanceDetailsLatest(ctx context.Context, purseIdentifier PurseIdentifier) (QueryBalanceDetailsResult, error) { +func (c *client) QueryBalanceDetailsByBlockHash(ctx context.Context, purseIdentifier PurseIdentifier, blockHash string) (QueryBalanceDetailsResult, error) { var result QueryBalanceDetailsResult - return result, c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{PurseIdentifier: purseIdentifier}, &result) + + resp, err := c.processRequest(ctx, MethodQueryBalanceDetails, QueryBalanceDetailsRequest{purseIdentifier, &GlobalStateIdentifier{ + BlockHash: &blockHash, + }}, &result) + if err != nil { + return QueryBalanceDetailsResult{}, err + } + + result.rawJSON = resp.Result + return result, nil } func (c *client) GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) { diff --git a/tests/rpc/integration/rpc_client_test.go b/tests/rpc/integration/rpc_client_test.go index 29c4ed5..25ba8a8 100644 --- a/tests/rpc/integration/rpc_client_test.go +++ b/tests/rpc/integration/rpc_client_test.go @@ -14,6 +14,7 @@ import ( "github.com/make-software/casper-go-sdk/casper" "github.com/make-software/casper-go-sdk/rpc" + "github.com/make-software/casper-go-sdk/types/key" ) func GetRpcClient() rpc.Client { @@ -46,71 +47,40 @@ func Test_DefaultClient_QueryBalanceDetails(t *testing.T) { ctx := context.Background() - tests := []struct { - name string - identifier rpc.BalanceStateIdentifier - }{ - { - name: "ByBlock", - identifier: rpc.BalanceStateIdentifier{ - Block: &rpc.BlockIdentifier{ - Height: &[]uint64{165520}[0], - }, - }, - }, - { - name: "ByBlockHash", - identifier: rpc.BalanceStateIdentifier{ - Block: &rpc.BlockIdentifier{ - Hash: &[]string{"ba48f6c4211a98ec0db3e62e95133a5b3cbd521107112cc115ed0ad84bd1083f"}[0], - }, - }, - }, - { - name: "ByStateRoot", - identifier: rpc.BalanceStateIdentifier{ - StateRoot: &rpc.StateRootInfo{ - StateRootHash: "281da1208effdfe4df196ddb83b862e4d11c5f58ddb1de4bfca4f8d43a51b6b4", - Timestamp: "2024-05-14T11:39:50.921Z", - }, - }, - }, - } - - entityAddr := "entity-account-" + pubKey.AccountHash().ToHex() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := GetRpcClient().QueryBalanceDetails(ctx, - rpc.PurseIdentifier{ - MainPurseUnderEntityAddr: &entityAddr, - }, - tt.identifier, - ) - require.NoError(t, err) - assert.NotEmpty(t, result.AvailableBalance) - assert.NotEmpty(t, result.TotalBalance) - assert.NotEmpty(t, result.TotalBalanceProof) - assert.Empty(t, result.Holds) - }) - } -} - -func Test_DefaultClient_QueryBalanceDetailsLatest(t *testing.T) { - pubKey, err := casper.NewPublicKey("0111bc2070a9af0f26f94b8549bffa5643ead0bc68eba3b1833039cfa2a9a8205d") + res, err := GetRpcClient().GetBlockLatest(ctx) require.NoError(t, err) - entityAddr := "entity-account-" + pubKey.AccountHash().ToHex() - t.Run("QueryBalanceDetailsLatest", func(t *testing.T) { - result, err := GetRpcClient().QueryBalanceDetailsLatest(context.Background(), - rpc.PurseIdentifier{ - MainPurseUnderEntityAddr: &entityAddr, - }, - ) + accountHash := pubKey.AccountHash() + assertResponse := func(result rpc.QueryBalanceDetailsResult, err error) { require.NoError(t, err) assert.NotEmpty(t, result.AvailableBalance) assert.NotEmpty(t, result.TotalBalance) assert.NotEmpty(t, result.TotalBalanceProof) - }) + assert.Empty(t, result.Holds) + } + + // latest call + assertResponse(GetRpcClient().QueryLatestBalanceDetails(ctx, rpc.NewPurseIdentifierFromAccountHash(accountHash))) + + // by BlockHeight and MainPurseUnderAccountHash + assertResponse(GetRpcClient().QueryBalanceDetailsByBlockHeight(ctx, + rpc.NewPurseIdentifierFromPublicKey(pubKey), + res.Block.Height, + )) + + // by BlockHash and MainPurseUnderEntityAddr + assertResponse(GetRpcClient().QueryBalanceDetailsByBlockHash(ctx, + rpc.NewPurseIdentifierFromAccountHash(accountHash), + res.Block.Hash.ToHex(), + )) + + // by StateRootHash and MainPurseUnderEntityAddr + assertResponse(GetRpcClient().QueryBalanceDetailsByStateRootHash(ctx, + rpc.NewPurseIdentifierFromEntityAddr(key.EntityAddr{ + Account: &accountHash.Hash, + }), + res.Block.StateRootHash.ToHex(), + )) } func Test_DefaultClient_QueryStateByStateHash(t *testing.T) { diff --git a/tests/rpc/rpc_client_test.go b/tests/rpc/rpc_client_test.go index 83b806b..81851c5 100644 --- a/tests/rpc/rpc_client_test.go +++ b/tests/rpc/rpc_client_test.go @@ -209,10 +209,10 @@ func Test_DefaultClient_GetStateBalance(t *testing.T) { defer server.Close() client := casper.NewRPCClient(casper.NewRPCHandler(server.URL, http.DefaultClient)) hash := "fb9c42717769d72442ff17a5ff1574b4bc1c83aedf5992b14e4d071423f86240" - result, err := client.GetAccountBalance( + result, err := client.GetBalance( context.Background(), - &hash, "uref-7b12008bb757ee32caefb3f7a1f77d9f659ee7a4e21ad4950c4e0294000492eb-007", + &hash, ) require.NoError(t, err) assert.Equal(t, "93000000000", result.BalanceValue.String()) @@ -222,10 +222,10 @@ func Test_DefaultClient_GetStateBalance_WithEmptyStateRootHash(t *testing.T) { server := SetupServer(t, "../data/rpc_response/get_account_balance.json") defer server.Close() client := casper.NewRPCClient(casper.NewRPCHandler(server.URL, http.DefaultClient)) - result, err := client.GetAccountBalance( + result, err := client.GetBalance( context.Background(), - nil, "uref-7b12008bb757ee32caefb3f7a1f77d9f659ee7a4e21ad4950c4e0294000492eb-007", + nil, ) require.NoError(t, err) assert.NotEmpty(t, result.BalanceValue) @@ -453,7 +453,7 @@ func Test_DefaultClient_QueryBalance_byPublicKey(t *testing.T) { pubKey, err := casper.NewPublicKey("0115394d1f395a87dfed4ab62bbfbc91b573bbb2bffb2c8ebb9c240c51d95bcc4d") require.NoError(t, err) client := casper.NewRPCClient(casper.NewRPCHandler(server.URL, http.DefaultClient)) - result, err := client.QueryBalance(context.Background(), rpc.PurseIdentifier{ + result, err := client.QueryLatestBalance(context.Background(), rpc.PurseIdentifier{ MainPurseUnderPublicKey: &pubKey, }) require.NoError(t, err) diff --git a/types/key/account.go b/types/key/account.go index 4ee7b15..8cb924c 100644 --- a/types/key/account.go +++ b/types/key/account.go @@ -23,7 +23,7 @@ func NewAccountHash(source string) (AccountHash, error) { return AccountHash{}, err } - return AccountHash{Hash: hexBytes, originPrefix: originPrefix}, err + return AccountHash{Hash: hexBytes, originPrefix: originPrefix}, nil } func (h *AccountHash) UnmarshalJSON(data []byte) error { diff --git a/types/key/balance_hold_addr.go b/types/key/balance_hold_addr.go index e384921..7965afd 100644 --- a/types/key/balance_hold_addr.go +++ b/types/key/balance_hold_addr.go @@ -124,7 +124,7 @@ func (h *BalanceHoldAddr) UnmarshalJSON(data []byte) error { } func (h BalanceHoldAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h BalanceHoldAddr) ToPrefixedString() string { diff --git a/types/key/bid_addr.go b/types/key/bid_addr.go index 77f6a87..59e9442 100644 --- a/types/key/bid_addr.go +++ b/types/key/bid_addr.go @@ -155,7 +155,7 @@ func (h *BidAddr) UnmarshalJSON(data []byte) error { } func (h BidAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h BidAddr) ToPrefixedString() string { diff --git a/types/key/block_global_addr.go b/types/key/block_global_addr.go index ca61c68..9bc4a66 100644 --- a/types/key/block_global_addr.go +++ b/types/key/block_global_addr.go @@ -54,7 +54,7 @@ func (h *BlockGlobalAddr) UnmarshalJSON(data []byte) error { } func (h BlockGlobalAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h BlockGlobalAddr) ToPrefixedString() string { diff --git a/types/key/byte_code.go b/types/key/byte_code.go index c9368d2..f0fea17 100644 --- a/types/key/byte_code.go +++ b/types/key/byte_code.go @@ -59,7 +59,7 @@ func (h ByteCode) IsEmpty() bool { } func (h ByteCode) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h ByteCode) ToPrefixedString() string { diff --git a/types/key/contract.go b/types/key/contract.go index 11eae0d..1b8062d 100644 --- a/types/key/contract.go +++ b/types/key/contract.go @@ -24,7 +24,7 @@ func (h *ContractHash) UnmarshalJSON(data []byte) error { } func (h ContractHash) MarshalJSON() ([]byte, error) { - return []byte(`"` + h.originPrefix + h.ToHex() + `"`), nil + return json.Marshal(h.originPrefix + h.ToHex()) } func (h ContractHash) ToPrefixedWasmString() string { diff --git a/types/key/contract_package.go b/types/key/contract_package.go index ff82231..30324a7 100644 --- a/types/key/contract_package.go +++ b/types/key/contract_package.go @@ -11,7 +11,7 @@ type ContractPackageHash struct { } func (h ContractPackageHash) MarshalJSON() ([]byte, error) { - return []byte(`"` + h.originPrefix + h.ToHex() + `"`), nil + return json.Marshal(h.originPrefix + h.ToHex()) } func (h ContractPackageHash) ToPrefixedString() string { diff --git a/types/key/entity_addr.go b/types/key/entity_addr.go index 14416ca..32db9ec 100644 --- a/types/key/entity_addr.go +++ b/types/key/entity_addr.go @@ -58,7 +58,7 @@ func (h *EntityAddr) UnmarshalJSON(data []byte) error { } func (h EntityAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h EntityAddr) ToPrefixedString() string { diff --git a/types/key/entry_point_addr.go b/types/key/entry_point_addr.go index 84c9edc..c4a1ac6 100644 --- a/types/key/entry_point_addr.go +++ b/types/key/entry_point_addr.go @@ -72,7 +72,7 @@ func (h *EntryPointAddr) UnmarshalJSON(data []byte) error { } func (h EntryPointAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h EntryPointAddr) ToPrefixedString() string { diff --git a/types/key/hash.go b/types/key/hash.go index 784ba1d..67f4522 100644 --- a/types/key/hash.go +++ b/types/key/hash.go @@ -53,7 +53,7 @@ func (h *Hash) UnmarshalText(text []byte) error { } func (h Hash) MarshalJSON() ([]byte, error) { - return []byte(`"` + h.ToHex() + `"`), nil + return json.Marshal(h.ToHex()) } func (h Hash) Bytes() []byte { diff --git a/types/key/message_addr.go b/types/key/message_addr.go index f4366b6..af5f531 100644 --- a/types/key/message_addr.go +++ b/types/key/message_addr.go @@ -67,7 +67,7 @@ func (h *MessageAddr) UnmarshalJSON(data []byte) error { } func (h MessageAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h MessageAddr) ToPrefixedString() string { diff --git a/types/key/named_key_addr.go b/types/key/named_key_addr.go index 7ed4217..dc636e3 100644 --- a/types/key/named_key_addr.go +++ b/types/key/named_key_addr.go @@ -51,7 +51,7 @@ func (h *NamedKeyAddr) UnmarshalJSON(data []byte) error { } func (h NamedKeyAddr) MarshalJSON() ([]byte, error) { - return []byte(h.ToPrefixedString()), nil + return json.Marshal(h.ToPrefixedString()) } func (h NamedKeyAddr) ToPrefixedString() string { diff --git a/types/key/transfer.go b/types/key/transfer.go index 6cd8795..300999a 100644 --- a/types/key/transfer.go +++ b/types/key/transfer.go @@ -42,5 +42,5 @@ func (h TransferHash) ToPrefixedString() string { } func (h TransferHash) MarshalJSON() ([]byte, error) { - return []byte(`"` + h.originPrefix + h.ToHex() + `"`), nil + return json.Marshal(h.originPrefix + h.ToHex()) } diff --git a/types/key/uref.go b/types/key/uref.go index 51de88d..c8f62fe 100644 --- a/types/key/uref.go +++ b/types/key/uref.go @@ -70,8 +70,7 @@ func (v *URef) UnmarshalText(text []byte) error { } func (v URef) MarshalJSON() ([]byte, error) { - s := v.ToPrefixedString() - return []byte(`"` + s + `"`), nil + return json.Marshal(v.ToPrefixedString()) } func (v *URef) GobDecode(i []byte) error { diff --git a/types/keypair/public_key.go b/types/keypair/public_key.go index bb84115..955b82a 100644 --- a/types/keypair/public_key.go +++ b/types/keypair/public_key.go @@ -97,7 +97,8 @@ func (v PublicKey) AccountHash() key.AccountHash { blakeHash := blake2b.Sum256(bytesToHash) data, _ := key.NewByteHashFromBuffer(bytes.NewBuffer(blakeHash[:])) - return key.AccountHash{Hash: data} + accountHash, _ := key.NewAccountHash(key.PrefixNameAccount + data.ToHex()) + return accountHash } func (v PublicKey) Value() (driver.Value, error) { From b1decab81ebaf5924cfec5fa06ec3ca3aef8caa9 Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 3 Jul 2024 19:40:57 +0200 Subject: [PATCH 5/5] CSDK-150/added_query_balance_details_rpc_endpoint Fixed after review --- rpc/client.go | 8 +++++--- rpc/rpc_client.go | 29 ++++++++++++++++++++--------- tests/rpc/rpc_client_test.go | 7 +++---- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index 67be5ce..7ec3221 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -45,10 +45,12 @@ type ClientPOS interface { // The response should be identical, regardless of the node queried, // as the information in question is objective and common to all nodes within a network. type ClientInformational interface { - // GetBalance returns a purse's balance from a network. + // GetLatestBalance returns a purse's balance from a network. // The request takes in the formatted representation of a purse URef as a parameter. - // If the param stateRootHash is nil, the client will make an additional RPC call to retrieve the latest stateRootHash. - GetBalance(ctx context.Context, purseURef string, stateRootHash *string) (StateGetBalanceResult, error) + // The client will make an additional RPC call to retrieve the latest stateRootHash. + GetLatestBalance(ctx context.Context, purseURef string) (StateGetBalanceResult, error) + // GetBalanceByStateRootHash returns a purse's balance and state root hash from a network. + GetBalanceByStateRootHash(ctx context.Context, purseURef string, stateRootHash string) (StateGetBalanceResult, error) // GetDeploy retrieves a Deploy from a network. It requires a deploy_hash to query the Deploy. GetDeploy(ctx context.Context, hash string) (InfoGetDeployResult, error) // GetDeployFinalizedApproval returns Deploy with the finalized approvals substituted. diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 6981a2f..112a3e5 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -204,18 +204,29 @@ func (c *client) GetDictionaryItemByIdentifier(ctx context.Context, stateRootHas return result, nil } -func (c *client) GetBalance(ctx context.Context, purseURef string, stateRootHash *string) (StateGetBalanceResult, error) { - if stateRootHash == nil { - latestHashResult, err := c.GetStateRootHashLatest(ctx) - if err != nil { - return StateGetBalanceResult{}, err - } - latestHashString := latestHashResult.StateRootHash.String() - stateRootHash = &latestHashString +func (c *client) GetLatestBalance(ctx context.Context, purseURef string) (StateGetBalanceResult, error) { + latestHashResult, err := c.GetStateRootHashLatest(ctx) + if err != nil { + return StateGetBalanceResult{}, err } + + var result StateGetBalanceResult + resp, err := c.processRequest(ctx, MethodGetStateBalance, map[string]string{ + "state_root_hash": latestHashResult.StateRootHash.String(), + "purse_uref": purseURef, + }, &result) + if err != nil { + return StateGetBalanceResult{}, err + } + + result.rawJSON = resp.Result + return result, nil +} + +func (c *client) GetBalanceByStateRootHash(ctx context.Context, purseURef string, stateRootHash string) (StateGetBalanceResult, error) { var result StateGetBalanceResult resp, err := c.processRequest(ctx, MethodGetStateBalance, map[string]string{ - "state_root_hash": *stateRootHash, + "state_root_hash": stateRootHash, "purse_uref": purseURef, }, &result) if err != nil { diff --git a/tests/rpc/rpc_client_test.go b/tests/rpc/rpc_client_test.go index 81851c5..cbd5484 100644 --- a/tests/rpc/rpc_client_test.go +++ b/tests/rpc/rpc_client_test.go @@ -209,10 +209,10 @@ func Test_DefaultClient_GetStateBalance(t *testing.T) { defer server.Close() client := casper.NewRPCClient(casper.NewRPCHandler(server.URL, http.DefaultClient)) hash := "fb9c42717769d72442ff17a5ff1574b4bc1c83aedf5992b14e4d071423f86240" - result, err := client.GetBalance( + result, err := client.GetBalanceByStateRootHash( context.Background(), "uref-7b12008bb757ee32caefb3f7a1f77d9f659ee7a4e21ad4950c4e0294000492eb-007", - &hash, + hash, ) require.NoError(t, err) assert.Equal(t, "93000000000", result.BalanceValue.String()) @@ -222,10 +222,9 @@ func Test_DefaultClient_GetStateBalance_WithEmptyStateRootHash(t *testing.T) { server := SetupServer(t, "../data/rpc_response/get_account_balance.json") defer server.Close() client := casper.NewRPCClient(casper.NewRPCHandler(server.URL, http.DefaultClient)) - result, err := client.GetBalance( + result, err := client.GetLatestBalance( context.Background(), "uref-7b12008bb757ee32caefb3f7a1f77d9f659ee7a4e21ad4950c4e0294000492eb-007", - nil, ) require.NoError(t, err) assert.NotEmpty(t, result.BalanceValue)