diff --git a/blockchain/endpointProviders/baseEndpointProvider.go b/blockchain/endpointProviders/baseEndpointProvider.go index 7391c07a..b5387499 100644 --- a/blockchain/endpointProviders/baseEndpointProvider.go +++ b/blockchain/endpointProviders/baseEndpointProvider.go @@ -18,6 +18,7 @@ const ( vmValues = "vm-values/query" genesisNodesConfig = "network/genesis-nodes" rawStartOfEpochMetaBlock = "internal/raw/startofepoch/metablock/by-epoch/%d" + nodeGetGuardianData = "/%s/guardian-data" ) type baseEndpointProvider struct{} @@ -92,6 +93,11 @@ func (base *baseEndpointProvider) GetGenesisNodesConfig() string { return genesisNodesConfig } +// GetGuardianData returns the guardian data endpoint +func (base *baseEndpointProvider) GetGuardianData(address string) string { + return fmt.Sprintf(nodeGetGuardianData, address) +} + // GetRawStartOfEpochMetaBlock returns the raw start of epoch metablock endpoint func (base *baseEndpointProvider) GetRawStartOfEpochMetaBlock(epoch uint32) string { return fmt.Sprintf(rawStartOfEpochMetaBlock, epoch) diff --git a/blockchain/endpointProviders/baseEndpointProvider_test.go b/blockchain/endpointProviders/baseEndpointProvider_test.go index bf45ff73..92cad273 100644 --- a/blockchain/endpointProviders/baseEndpointProvider_test.go +++ b/blockchain/endpointProviders/baseEndpointProvider_test.go @@ -25,4 +25,5 @@ func TestBaseEndpointProvider(t *testing.T) { assert.Equal(t, vmValues, base.GetVmValues()) assert.Equal(t, genesisNodesConfig, base.GetGenesisNodesConfig()) assert.Equal(t, "internal/raw/startofepoch/metablock/by-epoch/5", base.GetRawStartOfEpochMetaBlock(5)) + assert.Equal(t, "/dummyAddress/guardian-data", base.GetGuardianData("dummyAddress")) } diff --git a/blockchain/factory/interface.go b/blockchain/factory/interface.go index 6842278c..146d21b9 100644 --- a/blockchain/factory/interface.go +++ b/blockchain/factory/interface.go @@ -35,6 +35,7 @@ type EndpointProvider interface { GetRawBlockByHash(shardID uint32, hexHash string) string GetRawBlockByNonce(shardID uint32, nonce uint64) string GetRawMiniBlockByHash(shardID uint32, hexHash string, epoch uint32) string + GetGuardianData(address string) string GetRestAPIEntityType() core.RestAPIEntityType IsInterfaceNil() bool } diff --git a/blockchain/interface.go b/blockchain/interface.go index 96f82ac4..ad0c4a47 100644 --- a/blockchain/interface.go +++ b/blockchain/interface.go @@ -3,6 +3,7 @@ package blockchain import ( "context" + "github.com/ElrondNetwork/elrond-go-core/data/api" "github.com/ElrondNetwork/elrond-sdk-erdgo/core" "github.com/ElrondNetwork/elrond-sdk-erdgo/data" ) @@ -13,6 +14,7 @@ type Proxy interface { GetAccount(ctx context.Context, address core.AddressHandler) (*data.Account, error) SendTransaction(ctx context.Context, tx *data.Transaction) (string, error) SendTransactions(ctx context.Context, txs []*data.Transaction) ([]string, error) + GetGuardianData(ctx context.Context, address core.AddressHandler) (*api.GuardianData, error) ExecuteVMQuery(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) IsInterfaceNil() bool } @@ -45,6 +47,7 @@ type EndpointProvider interface { GetRawBlockByHash(shardID uint32, hexHash string) string GetRawBlockByNonce(shardID uint32, nonce uint64) string GetRawMiniBlockByHash(shardID uint32, hexHash string, epoch uint32) string + GetGuardianData(address string) string GetRestAPIEntityType() core.RestAPIEntityType IsInterfaceNil() bool } diff --git a/blockchain/proxy.go b/blockchain/proxy.go index 44b7268d..78d7d966 100644 --- a/blockchain/proxy.go +++ b/blockchain/proxy.go @@ -11,6 +11,7 @@ import ( "github.com/ElrondNetwork/elrond-go-core/core" "github.com/ElrondNetwork/elrond-go-core/core/check" + "github.com/ElrondNetwork/elrond-go-core/data/api" "github.com/ElrondNetwork/elrond-sdk-erdgo/blockchain/factory" erdgoCore "github.com/ElrondNetwork/elrond-sdk-erdgo/core" erdgoHttp "github.com/ElrondNetwork/elrond-sdk-erdgo/core/http" @@ -179,34 +180,34 @@ func (ep *elrondProxy) GetDefaultTransactionArguments( } return data.ArgCreateTransaction{ - Nonce: account.Nonce, - Value: "", - RcvAddr: "", - SndAddr: address.AddressAsBech32String(), - GasPrice: networkConfigs.MinGasPrice, - GasLimit: networkConfigs.MinGasLimit, - Data: nil, - Signature: "", - ChainID: networkConfigs.ChainID, - Version: networkConfigs.MinTransactionVersion, - Options: 0, - AvailableBalance: account.Balance, + Nonce: account.Nonce, + Value: "", + RcvAddr: "", + SndAddr: address.AddressAsBech32String(), + GasPrice: networkConfigs.MinGasPrice, + GasLimit: networkConfigs.MinGasLimit, + Data: nil, + Signature: "", + ChainID: networkConfigs.ChainID, + Version: networkConfigs.MinTransactionVersion, + Options: 0, + AvailableBalance: account.Balance, }, nil } // GetAccount retrieves an account info from the network (nonce, balance) func (ep *elrondProxy) GetAccount(ctx context.Context, address erdgoCore.AddressHandler) (*data.Account, error) { - err := ep.checkFinalState(ctx, address.AddressAsBech32String()) - if err != nil { - return nil, err - } - if check.IfNil(address) { return nil, ErrNilAddress } if !address.IsValid() { return nil, ErrInvalidAddress } + err := ep.checkFinalState(ctx, address.AddressAsBech32String()) + if err != nil { + return nil, err + } + endpoint := ep.endpointProvider.GetAccount(address.AddressAsBech32String()) buff, code, err := ep.GetHTTP(ctx, endpoint) @@ -539,6 +540,37 @@ func (ep *elrondProxy) GetGenesisNodesPubKeys(ctx context.Context) (*data.Genesi return response.Data.Nodes, nil } +// GetGuardianData retrieves guardian data from proxy +func (ep *elrondProxy) GetGuardianData(ctx context.Context, address erdgoCore.AddressHandler) (*api.GuardianData, error) { + if check.IfNil(address) { + return nil, ErrNilAddress + } + if !address.IsValid() { + return nil, ErrInvalidAddress + } + err := ep.checkFinalState(ctx, address.AddressAsBech32String()) + if err != nil { + return nil, err + } + + endpoint := ep.endpointProvider.GetGuardianData(address.AddressAsBech32String()) + buff, code, err := ep.GetHTTP(ctx, endpoint) + if err != nil || code != http.StatusOK { + return nil, createHTTPStatusError(code, err) + } + + response := &data.GuardianDataResponse{} + err = json.Unmarshal(buff, response) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, errors.New(response.Error) + } + + return response.Data.GuardianData, nil +} + // IsInterfaceNil returns true if there is no value under the interface func (ep *elrondProxy) IsInterfaceNil() bool { return ep == nil diff --git a/blockchain/proxy_test.go b/blockchain/proxy_test.go index 20c4a24d..04d4eaf2 100644 --- a/blockchain/proxy_test.go +++ b/blockchain/proxy_test.go @@ -15,6 +15,7 @@ import ( "github.com/ElrondNetwork/elrond-go-core/core" "github.com/ElrondNetwork/elrond-go-core/core/check" + "github.com/ElrondNetwork/elrond-go-core/data/api" erdgoCore "github.com/ElrondNetwork/elrond-sdk-erdgo/core" erdgoHttp "github.com/ElrondNetwork/elrond-sdk-erdgo/core/http" "github.com/ElrondNetwork/elrond-sdk-erdgo/data" @@ -221,6 +222,21 @@ func TestGetAccount(t *testing.T) { } expectedErr := errors.New("expected error") + t.Run("nil address should error", func(t *testing.T) { + t.Parallel() + + response, err := proxy.GetAccount(context.Background(), nil) + require.Equal(t, err, ErrNilAddress) + require.Nil(t, response) + }) + t.Run("invalid address should error", func(t *testing.T) { + t.Parallel() + + invalidAddress := data.NewAddressFromBytes([]byte("invalid address")) + response, err := proxy.GetAccount(context.Background(), invalidAddress) + require.Equal(t, err, ErrInvalidAddress) + require.Nil(t, response) + }) t.Run("finality checker errors should not query", func(t *testing.T) { proxy.finalityProvider = &testsCommon.FinalityProviderStub{ CheckShardFinalizationCalled: func(ctx context.Context, targetShardID uint32, maxNoncesDelta uint64) error { @@ -609,3 +625,64 @@ func TestElrondProxy_GetGenesisNodesPubKeys(t *testing.T) { require.Equal(t, expectedGenesisNodes, response) } + +func TestElrondProxy_GetGuardianData(t *testing.T) { + t.Parallel() + + t.Run("nil address should error", func(t *testing.T) { + t.Parallel() + + httpClient := createMockClientRespondingBytes([]byte("dummy response")) + args := createMockArgsElrondProxy(httpClient) + ep, _ := NewElrondProxy(args) + + response, err := ep.GetGuardianData(context.Background(), nil) + require.Equal(t, err, ErrNilAddress) + require.Nil(t, response) + }) + t.Run("invalid address should error", func(t *testing.T) { + t.Parallel() + + httpClient := createMockClientRespondingBytes([]byte("dummy response")) + args := createMockArgsElrondProxy(httpClient) + ep, _ := NewElrondProxy(args) + + address := data.NewAddressFromBytes([]byte("invalid address")) + response, err := ep.GetGuardianData(context.Background(), address) + require.Equal(t, err, ErrInvalidAddress) + require.Nil(t, response) + }) + t.Run("should work", func(t *testing.T) { + t.Parallel() + + expectedGuardianData := &api.GuardianData{ + ActiveGuardian: &api.Guardian{ + Address: "active guardian", + ActivationEpoch: 100, + }, + PendingGuardian: &api.Guardian{ + Address: "pending guardian", + ActivationEpoch: 200, + }, + Frozen: false, + } + guardianDataResponse := &data.GuardianDataResponse{ + Data: struct { + GuardianData *api.GuardianData `json:"guardianData"` + }{ + GuardianData: expectedGuardianData, + }, + } + guardianDataResponseBytes, _ := json.Marshal(guardianDataResponse) + + httpClient := createMockClientRespondingBytes(guardianDataResponseBytes) + args := createMockArgsElrondProxy(httpClient) + ep, _ := NewElrondProxy(args) + + address, _ := data.NewAddressFromBech32String("erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts") + response, err := ep.GetGuardianData(context.Background(), address) + require.Nil(t, err) + + require.Equal(t, expectedGuardianData, response) + }) +} diff --git a/data/guardian.go b/data/guardian.go new file mode 100644 index 00000000..b88db52f --- /dev/null +++ b/data/guardian.go @@ -0,0 +1,12 @@ +package data + +import "github.com/ElrondNetwork/elrond-go-core/data/api" + +// GuardianDataResponse holds the guardian data endpoint response +type GuardianDataResponse struct { + Data struct { + GuardianData *api.GuardianData `json:"guardianData"` + } `json:"data"` + Error string `json:"error"` + Code string `json:"code"` +} diff --git a/go.mod b/go.mod index f23d9a6d..80616e8c 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/ElrondNetwork/elrond-sdk-erdgo go 1.14 require ( - github.com/ElrondNetwork/elrond-go v1.3.38-0.20220901083346-925f26245a35 - github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220901061429-fc1143a4a107 + github.com/ElrondNetwork/elrond-go v1.3.38-0.20220912122303-9c2574322163 + github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220912122639-a040477c8cb7 github.com/ElrondNetwork/elrond-go-crypto v1.0.1 github.com/ElrondNetwork/elrond-go-logger v1.0.7 github.com/ElrondNetwork/elrond-vm-common v1.3.16-0.20220830135147-b69441f225cb diff --git a/go.sum b/go.sum index c1e91c68..ed5de73b 100644 --- a/go.sum +++ b/go.sum @@ -57,15 +57,16 @@ github.com/ElrondNetwork/covalent-indexer-go v1.0.6 h1:+LNKItUc+Pb7WuTbil3VuiLMm github.com/ElrondNetwork/covalent-indexer-go v1.0.6/go.mod h1:j3h2g96vqhJAuj3aEX2PWhomae2/o7YfXGEfweNXEeQ= github.com/ElrondNetwork/elastic-indexer-go v1.2.39 h1:NnhTF6yVnzAQNC7JibeGvR3anUSiA1I5UbWU9sn/U5E= github.com/ElrondNetwork/elastic-indexer-go v1.2.39/go.mod h1:w+J48ssy1kxOawG2lwiOUR4JYPA092g8Zjk88kRVDNA= -github.com/ElrondNetwork/elrond-go v1.3.38-0.20220901083346-925f26245a35 h1:k6vw0qpj2bgElK1defIECtRFL0oL5Z4+ZdtRjwNcZbc= -github.com/ElrondNetwork/elrond-go v1.3.38-0.20220901083346-925f26245a35/go.mod h1:KE8tiiWKRjTyGXrcJmooeXbNXOTKQs+M+xsR3WDFarY= +github.com/ElrondNetwork/elrond-go v1.3.38-0.20220912122303-9c2574322163 h1:eS3wI6XfhgW9UCflIzKufd9Ow71KrNSU+MIuCvLjcZ4= +github.com/ElrondNetwork/elrond-go v1.3.38-0.20220912122303-9c2574322163/go.mod h1:+9PRBuuTrlbAWB4bu5CNWNUVDEtLQHg58CcKw572Nbs= github.com/ElrondNetwork/elrond-go-core v1.0.0/go.mod h1:FQMem7fFF4+8pQ6lVsBZq6yO+smD0nV23P4bJpmPjTo= github.com/ElrondNetwork/elrond-go-core v1.1.7/go.mod h1:O9FkkTT2H9kxCzfn40TbhoCDXzGmUrRVusMomhK/Y3g= github.com/ElrondNetwork/elrond-go-core v1.1.15-0.20220517131228-41edc685421f/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM= github.com/ElrondNetwork/elrond-go-core v1.1.16-0.20220414130405-e3cc29bc7711/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM= github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220825075514-8e8d8ff0312b/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM= -github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220901061429-fc1143a4a107 h1:ix56Y1zvTenyEEJ5ujUrPbZrC7w3UxB6oTDTFXC8Ydo= -github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220901061429-fc1143a4a107/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM= +github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220902073302-7ec2dddbca2c/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM= +github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220912122639-a040477c8cb7 h1:ovTMzsZzCNgeHloV7ZPf4bDSTL9L77tzIffZdc9AxIY= +github.com/ElrondNetwork/elrond-go-core v1.1.20-0.20220912122639-a040477c8cb7/go.mod h1:Yz8JK5sGBctw7+gU8j2mZHbzQ09Ek4XHJ4Uinq1N6nM= github.com/ElrondNetwork/elrond-go-crypto v1.0.0/go.mod h1:DGiR7/j1xv729Xg8SsjYaUzWXL5svMd44REXjWS/gAc= github.com/ElrondNetwork/elrond-go-crypto v1.0.1 h1:xJUUshIZQ7h+rG7Art/9QHVyaPRV1wEjrxXYBdpmRlM= github.com/ElrondNetwork/elrond-go-crypto v1.0.1/go.mod h1:uunsvweBrrhVojL8uiQSaTPsl3YIQ9iBqtYGM6xs4s0= diff --git a/headerCheck/interface.go b/headerCheck/interface.go index 86f8a41b..e99eb149 100644 --- a/headerCheck/interface.go +++ b/headerCheck/interface.go @@ -4,7 +4,9 @@ import ( "context" coreData "github.com/ElrondNetwork/elrond-go-core/data" + "github.com/ElrondNetwork/elrond-go-core/data/api" "github.com/ElrondNetwork/elrond-go/state" + erdgoCore "github.com/ElrondNetwork/elrond-sdk-erdgo/core" "github.com/ElrondNetwork/elrond-sdk-erdgo/data" ) @@ -19,6 +21,7 @@ type Proxy interface { GetRawBlockByHash(ctx context.Context, shardId uint32, hash string) ([]byte, error) GetRawStartOfEpochMetaBlock(ctx context.Context, epoch uint32) ([]byte, error) GetGenesisNodesPubKeys(ctx context.Context) (*data.GenesisNodes, error) + GetGuardianData(ctx context.Context, address erdgoCore.AddressHandler) (*api.GuardianData, error) IsInterfaceNil() bool } diff --git a/testsCommon/proxyStub.go b/testsCommon/proxyStub.go index 3bd6bd73..16235344 100644 --- a/testsCommon/proxyStub.go +++ b/testsCommon/proxyStub.go @@ -4,6 +4,7 @@ import ( "context" "github.com/ElrondNetwork/elrond-go-core/core" + "github.com/ElrondNetwork/elrond-go-core/data/api" erdgoCore "github.com/ElrondNetwork/elrond-sdk-erdgo/core" "github.com/ElrondNetwork/elrond-sdk-erdgo/data" ) @@ -26,6 +27,7 @@ type ProxyStub struct { GetNetworkStatusCalled func(ctx context.Context, shardID uint32) (*data.NetworkStatus, error) GetShardOfAddressCalled func(ctx context.Context, bech32Address string) (uint32, error) GetRestAPIEntityTypeCalled func() erdgoCore.RestAPIEntityType + GetGuardianDataCalled func(ctx context.Context, address erdgoCore.AddressHandler) (*api.GuardianData, error) } // ExecuteVMQuery - @@ -170,6 +172,15 @@ func (stub *ProxyStub) GetRestAPIEntityType() erdgoCore.RestAPIEntityType { return "" } +// GetGuardianData - +func (stub *ProxyStub) GetGuardianData(ctx context.Context, address erdgoCore.AddressHandler) (*api.GuardianData, error) { + if stub.GetGuardianDataCalled != nil { + return stub.GetGuardianDataCalled(ctx, address) + } + + return &api.GuardianData{}, nil +} + // IsInterfaceNil - func (stub *ProxyStub) IsInterfaceNil() bool { return stub == nil