Skip to content

Commit

Permalink
Add pchain client
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoxiaff committed Jun 7, 2022
1 parent 8f9d67f commit bbaf332
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 56 deletions.
39 changes: 38 additions & 1 deletion mapper/helper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package mapper

import "strings"
import (
"errors"
"strings"

"github.com/ava-labs/avalanchego/utils/constants"
"github.com/coinbase/rosetta-sdk-go/types"
)

// EqualFoldContains checks if the array contains the string regardless of casing
func EqualFoldContains(arr []string, str string) bool {
Expand All @@ -11,3 +17,34 @@ func EqualFoldContains(arr []string, str string) bool {
}
return false
}

// IsPChain checks network identifier to make sure sub-network identifier set to "P"
func IsPChain(networkIdentifier *types.NetworkIdentifier) bool {
if networkIdentifier != nil &&
networkIdentifier.SubNetworkIdentifier != nil &&
networkIdentifier.SubNetworkIdentifier.Network == PChainNetworkIdentifier {
return true
}

return false
}

// GetAliasAndHRP fetches chain id alias and hrp for address formatting.
// Right now only P chain id alias is supported
func GetAliasAndHRP(networkIdentifier *types.NetworkIdentifier) (string, string, error) {
var chainIDAlias, hrp string
if !IsPChain(networkIdentifier) {
return "", "", errors.New("only support P chain alias")
}
chainIDAlias = PChainIDAlias
switch networkIdentifier.Network {
case FujiNetwork:
hrp = constants.GetHRP(constants.FujiID)
case MainnetNetwork:
hrp = constants.GetHRP(constants.MainnetID)
default:
return "", "", errors.New("can't recognize network")
}

return chainIDAlias, hrp, nil
}
46 changes: 46 additions & 0 deletions service/chain/p/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package p

import (
"context"

"github.com/ava-labs/avalanche-rosetta/mapper"
"github.com/ava-labs/avalanchego/utils/crypto"
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/coinbase/rosetta-sdk-go/types"
)

type Client struct {
fac crypto.FactorySECP256K1R
}

func NewClient() *Client {
return &Client{
fac: crypto.FactorySECP256K1R{},
}
}

func (c *Client) DeriveAddress(
ctx context.Context,
req *types.ConstructionDeriveRequest,
) (*types.ConstructionDeriveResponse, error) {
pub, err := c.fac.ToPublicKey(req.PublicKey.Bytes)
if err != nil {
return nil, err
}

chainIDAlias, hrp, getErr := mapper.GetAliasAndHRP(req.NetworkIdentifier)
if getErr != nil {
return nil, getErr
}

addr, err := address.Format(chainIDAlias, hrp, pub.Address().Bytes())
if err != nil {
return nil, err
}

return &types.ConstructionDeriveResponse{
AccountIdentifier: &types.AccountIdentifier{
Address: addr,
},
}, nil
}
33 changes: 0 additions & 33 deletions service/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import (
"math/big"
"strings"

"github.com/ava-labs/avalanchego/utils/constants"
ethtypes "github.com/ava-labs/coreth/core/types"
"github.com/coinbase/rosetta-sdk-go/types"
ethcommon "github.com/ethereum/go-ethereum/common"

"github.com/ava-labs/avalanche-rosetta/client"
"github.com/ava-labs/avalanche-rosetta/mapper"
)

const (
Expand Down Expand Up @@ -106,34 +104,3 @@ func ChecksumAddress(address string) (string, bool) {

return addr.Address().Hex(), true
}

// isPChain checks network identifier to make sure sub-network identifier set to "P"
func isPChain(networkIdentifier *types.NetworkIdentifier) bool {
if networkIdentifier != nil &&
networkIdentifier.SubNetworkIdentifier != nil &&
networkIdentifier.SubNetworkIdentifier.Network == mapper.PChainNetworkIdentifier {
return true
}

return false
}

// getAliasAndHRP fetches chain id alias and hrp for address formatting.
// Right now only P chain id alias is supported
func getAliasAndHRP(networkIdentifier *types.NetworkIdentifier) (string, string, *types.Error) {
var chainIDAlias, hrp string
if !isPChain(networkIdentifier) {
return "", "", makeError(errNotImplemented.Code, "only support P chain alias", false)
}
chainIDAlias = mapper.PChainIDAlias
switch networkIdentifier.Network {
case mapper.FujiNetwork:
hrp = constants.GetHRP(constants.FujiID)
case mapper.MainnetNetwork:
hrp = constants.GetHRP(constants.MainnetID)
default:
return "", "", makeError(errNotImplemented.Code, "can't recognize network", false)
}

return chainIDAlias, hrp, nil
}
28 changes: 7 additions & 21 deletions service/service_construction.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"fmt"
"math/big"

"github.com/ava-labs/avalanchego/utils/crypto"
"github.com/ava-labs/avalanchego/utils/formatting/address"
ethtypes "github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/interfaces"
"github.com/coinbase/rosetta-sdk-go/parser"
Expand All @@ -21,6 +19,7 @@ import (

"github.com/ava-labs/avalanche-rosetta/client"
"github.com/ava-labs/avalanche-rosetta/mapper"
"github.com/ava-labs/avalanche-rosetta/service/chain/p"
)

const (
Expand All @@ -34,13 +33,15 @@ const (
type ConstructionService struct {
config *Config
client client.Client
p *p.Client
}

// NewConstructionService returns a new construction servicer
func NewConstructionService(config *Config, client client.Client) server.ConstructionAPIServicer {
return &ConstructionService{
config: config,
client: client,
p: p.NewClient(),
}
}

Expand Down Expand Up @@ -226,28 +227,13 @@ func (s ConstructionService) ConstructionDerive(
ctx context.Context,
req *types.ConstructionDeriveRequest,
) (*types.ConstructionDeriveResponse, *types.Error) {
if isPChain(req.NetworkIdentifier) {
fac := crypto.FactorySECP256K1R{}
pub, err := fac.ToPublicKey(req.PublicKey.Bytes)
if mapper.IsPChain(req.NetworkIdentifier) {
res, err := s.p.DeriveAddress(ctx, req)
if err != nil {
return nil, wrapError(errInvalidInput, err)
}

chainIDAlias, hrp, getErr := getAliasAndHRP(req.NetworkIdentifier)
if getErr != nil {
return nil, getErr
return nil, wrapError(errInternalError, "p chain address derivation failed")
}

addr, err := address.Format(chainIDAlias, hrp, pub.Address().Bytes())
if err != nil {
return nil, wrapError(errInvalidInput, err)
}

return &types.ConstructionDeriveResponse{
AccountIdentifier: &types.AccountIdentifier{
Address: addr,
},
}, nil
return res, nil
}

if req.PublicKey == nil {
Expand Down
5 changes: 4 additions & 1 deletion service/service_construction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/ava-labs/avalanche-rosetta/mapper"
mocks "github.com/ava-labs/avalanche-rosetta/mocks/client"
"github.com/ava-labs/avalanche-rosetta/service/chain/p"
"github.com/ava-labs/coreth/interfaces"

"github.com/coinbase/rosetta-sdk-go/types"
Expand Down Expand Up @@ -238,7 +239,9 @@ func TestContructionHash(t *testing.T) {
}

func TestConstructionDerive(t *testing.T) {
service := ConstructionService{}
service := ConstructionService{
p: p.NewClient(),
}

t.Run("no public key", func(t *testing.T) {
resp, err := service.ConstructionDerive(
Expand Down

0 comments on commit bbaf332

Please sign in to comment.