Skip to content

Commit

Permalink
Merge pull request #360 from ava-labs/gstuart/hex-ids-api
Browse files Browse the repository at this point in the history
Decode hex or cb58
  • Loading branch information
geoff-vball authored Jul 10, 2024
2 parents 4ba6169 + 66d5f1d commit 7bcffc7
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 41 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ The relayer is configured via a JSON file, the path to which is passed in via th

`"source-blockchain-id": string`

- cb58-encoded blockchain ID of the source blockchain.
- cb58-encoded or "0x" prefixed hex-encoded blockchain ID of the source blockchain.

`"destination-blockchain-id": string`

- cb58-encoded blockchain ID of the destination blockchain.
- cb58-encoded or "0x" prefixed hex-encoded blockchain ID of the destination blockchain.

`"source-address": string`

Expand All @@ -219,11 +219,11 @@ The relayer is configured via a JSON file, the path to which is passed in via th

`"subnet-id": string`

- cb58-encoded Subnet ID.
- cb58-encoded or "0x" prefixed hex-encoded Subnet ID.

`"blockchain-id": string`

- cb58-encoded blockchain ID.
- cb58-encoded or "0x" prefixed hex-encoded blockchain ID.

`"vm": string`

Expand Down Expand Up @@ -263,11 +263,11 @@ The relayer is configured via a JSON file, the path to which is passed in via th

`"subnet-id": string`

- cb58-encoded Subnet ID.
- cb58-encoded or "0x" prefixed hex-encoded Subnet ID.

`"blockchain-id": string`

- cb58-encoded blockchain ID.
- cb58-encoded or "0x" prefixed hex-encoded blockchain ID.

`"vm": string`

Expand Down Expand Up @@ -322,8 +322,8 @@ The relayer consists of the following components:
- Used to manually relay a Warp message. The body of the request must contain the following JSON:
```json
{
"blockchain-id": "<cb58-encoding of blockchain ID>",
"message-id": "<cb58-encoding of Warp message ID>",
"blockchain-id": "<cb58-encoded or '0x' prefixed hex-encoded of blockchain ID>",
"message-id": "<cb58-encoded or '0x' prefixed hex-encoded of Warp message ID>",
"block-num": "<Block number that the message was sent in>"
}
```
Expand Down
13 changes: 6 additions & 7 deletions api/relay_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import (
"math/big"
"net/http"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/awm-relayer/relayer"
"github.com/ava-labs/awm-relayer/types"
relayerTypes "github.com/ava-labs/awm-relayer/types"
"github.com/ava-labs/awm-relayer/utils"
"github.com/ethereum/go-ethereum/common"
"go.uber.org/zap"
)
Expand All @@ -20,9 +19,9 @@ const (
)

type RelayMessageRequest struct {
// Required. cb58 encoding of the source blockchain ID for the message
// Required. cb58-encoded or "0x" prefixed hex-encoded source blockchain ID for the message
BlockchainID string `json:"blockchain-id"`
// Required. cb58 encoding of the warp message ID
// Required. cb58-encoded or "0x" prefixed hex-encoded warp message ID
MessageID string `json:"message-id"`
// Required. Block number that the message was sent in
BlockNum uint64 `json:"block-num"`
Expand Down Expand Up @@ -64,7 +63,7 @@ func relayMessageAPIHandler(logger logging.Logger, messageCoordinator *relayer.M
return
}

warpMessageInfo := &relayerTypes.WarpMessageInfo{
warpMessageInfo := &types.WarpMessageInfo{
SourceAddress: common.HexToAddress(req.SourceAddress),
UnsignedMessage: unsignedMessage,
}
Expand Down Expand Up @@ -104,13 +103,13 @@ func relayAPIHandler(logger logging.Logger, messageCoordinator *relayer.MessageC
return
}

blockchainID, err := ids.FromString(req.BlockchainID)
blockchainID, err := utils.HexOrCB58ToID(req.BlockchainID)
if err != nil {
logger.Warn("Invalid blockchainID", zap.String("blockchainID", req.BlockchainID))
http.Error(w, "invalid blockchainID: "+err.Error(), http.StatusBadRequest)
return
}
messageID, err := ids.FromString(req.MessageID)
messageID, err := utils.HexOrCB58ToID(req.MessageID)
if err != nil {
logger.Warn("Invalid messageID", zap.String("messageID", req.MessageID))
http.Error(w, "invalid messageID: "+err.Error(), http.StatusBadRequest)
Expand Down
19 changes: 5 additions & 14 deletions config/destination_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,8 @@ type DestinationBlockchain struct {
blockchainID ids.ID
}

// Validatees the destination subnet configuration
// Validates the destination subnet configuration
func (s *DestinationBlockchain) Validate() error {
if _, err := ids.FromString(s.SubnetID); err != nil {
return fmt.Errorf("invalid subnetID in destination subnet configuration. Provided ID: %s", s.SubnetID)
}
if _, err := ids.FromString(s.BlockchainID); err != nil {
return fmt.Errorf(
"invalid blockchainID in destination subnet configuration. Provided ID: %s",
s.BlockchainID,
)
}
if err := s.RPCEndpoint.Validate(); err != nil {
return fmt.Errorf("invalid rpc-endpoint in destination subnet configuration: %w", err)
}
Expand All @@ -63,14 +54,14 @@ func (s *DestinationBlockchain) Validate() error {
}

// Validate and store the subnet and blockchain IDs for future use
blockchainID, err := ids.FromString(s.BlockchainID)
blockchainID, err := utils.HexOrCB58ToID(s.BlockchainID)
if err != nil {
return fmt.Errorf("invalid blockchainID in configuration. error: %w", err)
return fmt.Errorf("invalid blockchainID '%s' in configuration. error: %w", s.BlockchainID, err)
}
s.blockchainID = blockchainID
subnetID, err := ids.FromString(s.SubnetID)
subnetID, err := utils.HexOrCB58ToID(s.SubnetID)
if err != nil {
return fmt.Errorf("invalid subnetID in configuration. error: %w", err)
return fmt.Errorf("invalid subnetID '%s' in configuration. error: %w", s.SubnetID, err)
}
s.subnetID = subnetID

Expand Down
19 changes: 7 additions & 12 deletions config/source_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ type SourceBlockchain struct {
// destinationBlockchainIDs. Does not modify the public fields as derived from the configuration passed to the
// application, but does initialize private fields available through getters.
func (s *SourceBlockchain) Validate(destinationBlockchainIDs *set.Set[string]) error {
if _, err := ids.FromString(s.SubnetID); err != nil {
return fmt.Errorf("invalid subnetID in source subnet configuration. Provided ID: %s", s.SubnetID)
}
if _, err := ids.FromString(s.BlockchainID); err != nil {
return fmt.Errorf("invalid blockchainID in source subnet configuration. Provided ID: %s", s.BlockchainID)
}
if err := s.RPCEndpoint.Validate(); err != nil {
return fmt.Errorf("invalid rpc-endpoint in source subnet configuration: %w", err)
}
Expand Down Expand Up @@ -79,14 +73,14 @@ func (s *SourceBlockchain) Validate(destinationBlockchainIDs *set.Set[string]) e
}

// Validate and store the subnet and blockchain IDs for future use
blockchainID, err := ids.FromString(s.BlockchainID)
blockchainID, err := utils.HexOrCB58ToID(s.BlockchainID)
if err != nil {
return fmt.Errorf("invalid blockchainID in configuration. error: %w", err)
return fmt.Errorf("invalid blockchainID '%s' in configuration. error: %w", s.BlockchainID, err)
}
s.blockchainID = blockchainID
subnetID, err := ids.FromString(s.SubnetID)
subnetID, err := utils.HexOrCB58ToID(s.SubnetID)
if err != nil {
return fmt.Errorf("invalid subnetID in configuration. error: %w", err)
return fmt.Errorf("invalid subnetID '%s' in configuration. error: %w", s.SubnetID, err)
}
s.subnetID = subnetID

Expand All @@ -99,15 +93,16 @@ func (s *SourceBlockchain) Validate(destinationBlockchainIDs *set.Set[string]) e
}
}
for _, dest := range s.SupportedDestinations {
blockchainID, err := ids.FromString(dest.BlockchainID)
blockchainID, err := utils.HexOrCB58ToID(dest.BlockchainID)
if err != nil {
return fmt.Errorf("invalid blockchainID in configuration. error: %w", err)
}
if !destinationBlockchainIDs.Contains(dest.BlockchainID) {
return fmt.Errorf(
"configured source subnet %s has a supported destination blockchain ID %s that is not configured as a destination blockchain", //nolint:lll
s.SubnetID,
blockchainID)
blockchainID,
)
}
dest.blockchainID = blockchainID
for _, addressStr := range dest.Addresses {
Expand Down
14 changes: 14 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"
"time"

"github.com/ava-labs/avalanchego/ids"
"github.com/ethereum/go-ethereum/common"
)

Expand Down Expand Up @@ -123,3 +124,16 @@ func StripFromString(input, substring string) string {

return strippedString
}

// Converts a '0x'-prefixed hex string or cb58-encoded string to an ID.
// Input length validation is handled by the ids package.
func HexOrCB58ToID(s string) (ids.ID, error) {
if strings.HasPrefix(s, "0x") {
bytes, err := hex.DecodeString(SanitizeHexString(s))
if err != nil {
return ids.ID{}, err
}
return ids.ToID(bytes)
}
return ids.FromString(s)
}
38 changes: 38 additions & 0 deletions utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,44 @@ import (
"github.com/stretchr/testify/require"
)

func TestHexOrCB58ToID(t *testing.T) {
testCases := []struct {
name string
encoding string
expectedResult string
errorExpected bool
}{
{
name: "hex conversion",
encoding: "0x7fc93d85c6d62c5b2ac0b519c87010ea5294012d1e407030d6acd0021cac10d5",
expectedResult: "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp",
errorExpected: false,
},
{
name: "cb58 conversion",
encoding: "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp",
expectedResult: "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp",
errorExpected: false,
},
{
name: "non-prefixed hex",
encoding: "7fc93d85c6d62c5b2ac0b519c87010ea5294012d1e407030d6acd0021cac10d5",
errorExpected: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
actualResult, err := HexOrCB58ToID(testCase.encoding)
if testCase.errorExpected {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, testCase.expectedResult, actualResult.String())
}
})
}
}

func TestSanitizeHexString(t *testing.T) {
testCases := []struct {
name string
Expand Down

0 comments on commit 7bcffc7

Please sign in to comment.