Skip to content

Commit

Permalink
Merge pull request #6123 from multiversx/MX-15381-add-withKeys-on-api…
Browse files Browse the repository at this point in the history
…-address

add withKeys option on account
  • Loading branch information
miiu96 authored Apr 24, 2024
2 parents e5c9201 + c0a6756 commit 52a19be
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 40 deletions.
9 changes: 9 additions & 0 deletions api/groups/addressGroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
urlParamBlockHash = "blockHash"
urlParamBlockRootHash = "blockRootHash"
urlParamHintEpoch = "hintEpoch"
urlParamWithKeys = "withKeys"
)

// addressFacadeHandler defines the methods to be implemented by a facade for handling address requests
Expand Down Expand Up @@ -185,6 +186,14 @@ func (ag *addressGroup) getAccount(c *gin.Context) {
return
}

withKeys, err := parseBoolUrlParam(c, urlParamWithKeys)
if err != nil {
shared.RespondWithValidationError(c, errors.ErrCouldNotGetAccount, err)
return
}

options.WithKeys = withKeys

accountResponse, blockInfo, err := ag.getFacade().GetAccount(addr, options)
if err != nil {
shared.RespondWithInternalError(c, errors.ErrCouldNotGetAccount, err)
Expand Down
4 changes: 4 additions & 0 deletions facade/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ type NodeHandler interface {
// about the account correlated with provided address
GetAccount(address string, options api.AccountQueryOptions) (api.AccountResponse, api.BlockInfo, error)

// GetAccountWithKeys returns an accountResponse containing information
// about the account correlated with provided address and all keys
GetAccountWithKeys(address string, options api.AccountQueryOptions, ctx context.Context) (api.AccountResponse, api.BlockInfo, error)

// GetCode returns the code for the given code hash
GetCode(codeHash []byte, options api.AccountQueryOptions) ([]byte, api.BlockInfo)

Expand Down
10 changes: 10 additions & 0 deletions facade/mock/nodeStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type NodeStub struct {
ValidateTransactionForSimulationCalled func(tx *transaction.Transaction, bypassSignature bool) error
SendBulkTransactionsHandler func(txs []*transaction.Transaction) (uint64, error)
GetAccountCalled func(address string, options api.AccountQueryOptions) (api.AccountResponse, api.BlockInfo, error)
GetAccountWithKeysCalled func(address string, options api.AccountQueryOptions, ctx context.Context) (api.AccountResponse, api.BlockInfo, error)
GetCodeCalled func(codeHash []byte, options api.AccountQueryOptions) ([]byte, api.BlockInfo)
GetCurrentPublicKeyHandler func() string
GenerateAndSendBulkTransactionsHandler func(destination string, value *big.Int, nrTransactions uint64) error
Expand Down Expand Up @@ -189,6 +190,15 @@ func (ns *NodeStub) GetAccount(address string, options api.AccountQueryOptions)
return api.AccountResponse{}, api.BlockInfo{}, nil
}

// GetAccountWithKeys -
func (ns *NodeStub) GetAccountWithKeys(address string, options api.AccountQueryOptions, ctx context.Context) (api.AccountResponse, api.BlockInfo, error) {
if ns.GetAccountWithKeysCalled != nil {
return ns.GetAccountWithKeysCalled(address, options, ctx)
}

return api.AccountResponse{}, api.BlockInfo{}, nil
}

// GetCode -
func (ns *NodeStub) GetCode(codeHash []byte, options api.AccountQueryOptions) ([]byte, api.BlockInfo) {
if ns.GetCodeCalled != nil {
Expand Down
26 changes: 22 additions & 4 deletions facade/nodeFacade.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,19 @@ func (nf *nodeFacade) ComputeTransactionGasLimit(tx *transaction.Transaction) (*

// GetAccount returns a response containing information about the account correlated with provided address
func (nf *nodeFacade) GetAccount(address string, options apiData.AccountQueryOptions) (apiData.AccountResponse, apiData.BlockInfo, error) {
accountResponse, blockInfo, err := nf.node.GetAccount(address, options)
var accountResponse apiData.AccountResponse
var blockInfo apiData.BlockInfo
var err error

if options.WithKeys {
ctx, cancel := nf.getContextForApiTrieRangeOperations()
defer cancel()

accountResponse, blockInfo, err = nf.node.GetAccountWithKeys(address, options, ctx)
} else {
accountResponse, blockInfo, err = nf.node.GetAccount(address, options)
}

if err != nil {
return apiData.AccountResponse{}, apiData.BlockInfo{}, err
}
Expand All @@ -359,13 +371,19 @@ func (nf *nodeFacade) GetAccounts(addresses []string, options apiData.AccountQue
response := make(map[string]*apiData.AccountResponse)
var blockInfo apiData.BlockInfo

for _, address := range addresses {
for i, address := range addresses {
accountResponse, blockInfoForAccount, err := nf.node.GetAccount(address, options)
if err != nil {
return nil, apiData.BlockInfo{}, err
}

blockInfo = blockInfoForAccount
// Use the first block info as the block info for the whole bulk
if i == 0 {
blockInfo = blockInfoForAccount
blockRootHash, errBlockRootHash := hex.DecodeString(blockInfoForAccount.RootHash)
if errBlockRootHash == nil {
options.BlockRootHash = blockRootHash
}
}

codeHash := accountResponse.CodeHash
code, _ := nf.node.GetCode(codeHash, options)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/klauspost/cpuid/v2 v2.2.5
github.com/mitchellh/mapstructure v1.5.0
github.com/multiversx/mx-chain-communication-go v1.0.14
github.com/multiversx/mx-chain-core-go v1.2.19
github.com/multiversx/mx-chain-core-go v1.2.20
github.com/multiversx/mx-chain-crypto-go v1.2.11
github.com/multiversx/mx-chain-es-indexer-go v1.4.21
github.com/multiversx/mx-chain-logger-go v1.0.14
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,8 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY
github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o=
github.com/multiversx/mx-chain-communication-go v1.0.14 h1:YhAUDjBBpc5h5W0A7LHLXUMIMeCgwgGvkqfAPbFqsno=
github.com/multiversx/mx-chain-communication-go v1.0.14/go.mod h1:qYCqgk0h+YpcTA84jHIpCBy6UShRwmXzHSCcdfwNrkw=
github.com/multiversx/mx-chain-core-go v1.2.19 h1:2BaVHkB0tro3cjs5ay2pmLup1loCV0e1p9jV5QW0xqc=
github.com/multiversx/mx-chain-core-go v1.2.19/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE=
github.com/multiversx/mx-chain-core-go v1.2.20 h1:jOQ10LxxUqECnuqUYeBBT6VoZcpJDdYgOvsSGtifDdI=
github.com/multiversx/mx-chain-core-go v1.2.20/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE=
github.com/multiversx/mx-chain-crypto-go v1.2.11 h1:MNPJoiTJA5/tedYrI0N22OorbsKDESWG0SF8MCJwcJI=
github.com/multiversx/mx-chain-crypto-go v1.2.11/go.mod h1:pcZutPdfLiAFytzCU3LxU3s8cXkvpNqquyitFSfoF3o=
github.com/multiversx/mx-chain-es-indexer-go v1.4.21 h1:rzxXCkgOsqj67GRYtqzKuf9XgHwnZLTZhU90Ck3VbrE=
Expand Down
124 changes: 91 additions & 33 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ type filter interface {
filter(tokenIdentifier string, esdtData *systemSmartContracts.ESDTDataV2) bool
}

type accountInfo struct {
account state.UserAccountHandler
block api.BlockInfo
accountResponse api.AccountResponse
}

// Node is a structure that holds all managed components
type Node struct {
initialNodesPubkeys map[uint32][]string
Expand Down Expand Up @@ -291,13 +297,26 @@ func (n *Node) GetKeyValuePairs(address string, options api.AccountQueryOptions,
return map[string]string{}, api.BlockInfo{}, nil
}

mapToReturn, err := n.getKeys(userAccount, ctx)
if err != nil {
return nil, api.BlockInfo{}, err
}

if common.IsContextDone(ctx) {
return nil, api.BlockInfo{}, ErrTrieOperationsTimeout
}

return mapToReturn, blockInfo, nil
}

func (n *Node) getKeys(userAccount state.UserAccountHandler, ctx context.Context) (map[string]string, error) {
chLeaves := &common.TrieIteratorChannels{
LeavesChan: make(chan core.KeyValueHolder, common.TrieLeavesChannelDefaultCapacity),
ErrChan: errChan.NewErrChanWrapper(),
}
err = userAccount.GetAllLeaves(chLeaves, ctx)
err := userAccount.GetAllLeaves(chLeaves, ctx)
if err != nil {
return nil, api.BlockInfo{}, err
return nil, err
}

mapToReturn := make(map[string]string)
Expand All @@ -307,14 +326,9 @@ func (n *Node) GetKeyValuePairs(address string, options api.AccountQueryOptions,

err = chLeaves.ErrChan.ReadFromChanNonBlocking()
if err != nil {
return nil, api.BlockInfo{}, err
}

if common.IsContextDone(ctx) {
return nil, api.BlockInfo{}, ErrTrieOperationsTimeout
return nil, err
}

return mapToReturn, blockInfo, nil
return mapToReturn, nil
}

// GetValueForKey will return the value for a key from a given account
Expand Down Expand Up @@ -931,40 +945,32 @@ func (n *Node) setTxGuardianData(guardian string, guardianSigHex string, tx *tra

// GetAccount will return account details for a given address
func (n *Node) GetAccount(address string, options api.AccountQueryOptions) (api.AccountResponse, api.BlockInfo, error) {
account, blockInfo, err := n.loadUserAccountHandlerByAddress(address, options)
accInfo, err := n.getAccountInfo(address, options)
if err != nil {
adaptedBlockInfo, isEmptyAccount := extractBlockInfoIfNewAccount(err)
if isEmptyAccount {
return api.AccountResponse{
Address: address,
Balance: "0",
DeveloperReward: "0",
}, adaptedBlockInfo, nil
}
return api.AccountResponse{}, api.BlockInfo{}, err
}

return accInfo.accountResponse, accInfo.block, nil
}

// GetAccountWithKeys will return account details for a given address including the keys
func (n *Node) GetAccountWithKeys(address string, options api.AccountQueryOptions, ctx context.Context) (api.AccountResponse, api.BlockInfo, error) {
accInfo, err := n.getAccountInfo(address, options)
if err != nil {
return api.AccountResponse{}, api.BlockInfo{}, err
}

ownerAddress := ""
if len(account.GetOwnerAddress()) > 0 {
addressPubkeyConverter := n.coreComponents.AddressPubKeyConverter()
ownerAddress, err = addressPubkeyConverter.Encode(account.GetOwnerAddress())
var keys map[string]string
if options.WithKeys {
keys, err = n.getKeys(accInfo.account, ctx)
if err != nil {
return api.AccountResponse{}, api.BlockInfo{}, err
}
}

return api.AccountResponse{
Address: address,
Nonce: account.GetNonce(),
Balance: account.GetBalance().String(),
Username: string(account.GetUserName()),
CodeHash: account.GetCodeHash(),
RootHash: account.GetRootHash(),
CodeMetadata: account.GetCodeMetadata(),
DeveloperReward: account.GetDeveloperReward().String(),
OwnerAddress: ownerAddress,
}, blockInfo, nil
accInfo.accountResponse.Pairs = keys

return accInfo.accountResponse, accInfo.block, nil
}

func extractBlockInfoIfNewAccount(err error) (api.BlockInfo, bool) {
Expand All @@ -984,6 +990,58 @@ func extractBlockInfoIfNewAccount(err error) (api.BlockInfo, bool) {
return api.BlockInfo{}, false
}

func (n *Node) getAccountInfo(address string, options api.AccountQueryOptions) (accountInfo, error) {
account, blockInfo, err := n.loadUserAccountHandlerByAddress(address, options)
if err != nil {
adaptedBlockInfo, isEmptyAccount := extractBlockInfoIfNewAccount(err)
if isEmptyAccount {
return accountInfo{
accountResponse: api.AccountResponse{
Address: address,
Balance: "0",
DeveloperReward: "0",
},
block: adaptedBlockInfo,
account: account,
}, nil
}
return accountInfo{
accountResponse: api.AccountResponse{},
block: api.BlockInfo{},
account: nil,
}, err
}

ownerAddress := ""
if len(account.GetOwnerAddress()) > 0 {
addressPubkeyConverter := n.coreComponents.AddressPubKeyConverter()
ownerAddress, err = addressPubkeyConverter.Encode(account.GetOwnerAddress())
if err != nil {
return accountInfo{
accountResponse: api.AccountResponse{},
block: api.BlockInfo{},
account: nil,
}, err
}
}

return accountInfo{
accountResponse: api.AccountResponse{
Address: address,
Nonce: account.GetNonce(),
Balance: account.GetBalance().String(),
Username: string(account.GetUserName()),
CodeHash: account.GetCodeHash(),
RootHash: account.GetRootHash(),
CodeMetadata: account.GetCodeMetadata(),
DeveloperReward: account.GetDeveloperReward().String(),
OwnerAddress: ownerAddress,
},
block: blockInfo,
account: account,
}, nil
}

// GetCode returns the code for the given code hash
func (n *Node) GetCode(codeHash []byte, options api.AccountQueryOptions) ([]byte, api.BlockInfo) {
return n.loadAccountCode(codeHash, options)
Expand Down
Loading

0 comments on commit 52a19be

Please sign in to comment.