[rpc] added multiaddress in GetDelegationsByDelegatorByBlockNumber

pull/3718/head
Jacky Wang 4 years ago committed by Leo Chen
parent b0bf39861d
commit ce6e4c1f4c
  1. 41
      rpc/staking.go
  2. 46
      rpc/types.go
  3. 72
      rpc/types_test.go

@ -5,6 +5,9 @@ import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -501,8 +504,8 @@ func (s *PublicStakingService) GetDelegationsByDelegator(
// GetDelegationsByDelegatorByBlockNumber returns list of delegations for a delegator address at given block number
func (s *PublicStakingService) GetDelegationsByDelegatorByBlockNumber(
ctx context.Context, address string, blockNumber BlockNumber,
) ([]StructuredResponse, error) {
ctx context.Context, aol AddressOrList, blockNumber BlockNumber,
) (interface{}, error) {
// Process number based on version
blockNum := blockNumber.EthBlockNumber()
@ -512,20 +515,34 @@ func (s *PublicStakingService) GetDelegationsByDelegatorByBlockNumber(
if isBlockGreaterThanLatest(s.hmy, blockNum) {
return nil, ErrRequestedBlockTooHigh
}
// Fetch delegation for block number
delegatorAddress, err := internal_common.ParseAddr(address)
if err != nil {
return nil, err
}
blk, err := s.hmy.BlockByNumber(ctx, blockNum)
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the blk information for blk number: %d", blockNum)
}
validators, delegations := s.hmy.GetDelegationsByDelegatorByBlock(delegatorAddress, blk)
// Format response
result := []StructuredResponse{}
if aol.Address != nil { // single address
delegatorAddress := *aol.Address
validators, delegations := s.hmy.GetDelegationsByDelegatorByBlock(delegatorAddress, blk)
return s.parseGetDelegationsByDelegatorResp(delegatorAddress, validators, delegations)
} else { // multiple address
srs := make([][]StructuredResponse, 0, len(aol.AddressList))
for _, delegatorAddress := range aol.AddressList {
validators, delegations := s.hmy.GetDelegationsByDelegatorByBlock(delegatorAddress, blk)
res, err := s.parseGetDelegationsByDelegatorResp(delegatorAddress, validators, delegations)
if err != nil {
return nil, err
}
srs = append(srs, res)
}
return srs, nil
}
}
func (s *PublicStakingService) parseGetDelegationsByDelegatorResp(
delegator common.Address, validators []common.Address, delegations []*staking.Delegation,
) ([]StructuredResponse, error) {
var result []StructuredResponse
for i := range delegations {
delegation := delegations[i]
undelegations := make([]Undelegation, len(delegation.Undelegations))
@ -537,7 +554,7 @@ func (s *PublicStakingService) GetDelegationsByDelegatorByBlockNumber(
}
}
valAddr, _ := internal_common.AddressToBech32(validators[i])
delAddr, _ := internal_common.AddressToBech32(delegatorAddress)
delAddr, _ := internal_common.AddressToBech32(delegator)
// Response output is the same for all versions
del, err := NewStructuredResponse(Delegation{

@ -4,11 +4,15 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
"time"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/pkg/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
@ -246,3 +250,45 @@ func NewHeaderInformation(header *block.Header, leader string) *HeaderInformatio
return result
}
// AddressOrList represents an address or a list of addresses
type AddressOrList struct {
Address *common.Address
AddressList []common.Address
}
// UnmarshalJSON defines the input parsing of AddressOrList
func (aol *AddressOrList) UnmarshalJSON(data []byte) (err error) {
var itf interface{}
if err := json.Unmarshal(data, &itf); err != nil {
return err
}
switch d := itf.(type) {
case string: // Single address
addr, err := internal_common.ParseAddr(d)
if err != nil {
return err
}
aol.Address = &addr
return nil
case []interface{}: // Address array
var addrs []common.Address
for _, addrItf := range d {
addrStr, ok := addrItf.(string)
if !ok {
return errors.New("not invalid address array")
}
addr, err := internal_common.ParseAddr(addrStr)
if err != nil {
return fmt.Errorf("invalid address: %v", addrStr)
}
addrs = append(addrs, addr)
}
aol.AddressList = addrs
return nil
default:
return errors.New("must provide one address or address list")
}
}

@ -0,0 +1,72 @@
package rpc
import (
"encoding/json"
"fmt"
"testing"
"github.com/ethereum/go-ethereum/common"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/pkg/errors"
)
var (
testAddr1Str = "one1upj2dzv5ayuqy5x0aclgcr32chqfy32glsdusk"
testAddr2Str = "one1k860e6h0sen6ap5fymzwpqtmqlkut2fcus840l"
testAddr1JStr = fmt.Sprintf(`"%v"`, testAddr1Str)
testAddr2JStr = fmt.Sprintf(`"%v"`, testAddr2Str)
testAddr1, _ = internal_common.Bech32ToAddress(testAddr1Str)
testAddr2, _ = internal_common.Bech32ToAddress(testAddr2Str)
)
func TestAddressOrList_UnmarshalJSON(t *testing.T) {
tests := []struct {
input string
exp AddressOrList
}{
{
input: testAddr1JStr,
exp: AddressOrList{
Address: &testAddr1,
AddressList: nil,
},
},
{
input: fmt.Sprintf("[%v, %v]", testAddr1JStr, testAddr2JStr),
exp: AddressOrList{
Address: nil,
AddressList: []common.Address{testAddr1, testAddr2},
},
},
}
for _, test := range tests {
var aol *AddressOrList
if err := json.Unmarshal([]byte(test.input), &aol); err != nil {
t.Fatal(err)
}
if err := checkAddressOrListEqual(aol, &test.exp); err != nil {
t.Error(err)
}
}
}
func checkAddressOrListEqual(a, b *AddressOrList) error {
if (a.Address != nil) != (b.Address != nil) {
return errors.New("address not equal")
}
if a.Address != nil && *a.Address != *b.Address {
return errors.New("address not equal")
}
if len(a.AddressList) != len(b.AddressList) {
return errors.New("address list size not equal")
}
for i, addr1 := range a.AddressList {
addr2 := b.AddressList[i]
if addr1 != addr2 {
return errors.New("address list elem not equal")
}
}
return nil
}
Loading…
Cancel
Save