[API] Accept additional address formats (#170)
### Summary Context: https://github.com/wormhole-foundation/wormhole-explorer/issues/154 This PR modifies all endpoints that receive an emitter/guardian address to accept a wider range of formats. After this pull request, all of these are equivalent: * `0x000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7` * `000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7` * `0xf890982f9310df57d00f659cf4fd87e65aded8d7` * `f890982f9310df57d00f659cf4fd87e65aded8d7` ### Testing plan * Added unit tests for the parsing code. * Tested manually a few of the affected endpoints.
This commit is contained in:
parent
b1583d5e21
commit
533b83ad28
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
errs "github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
|
@ -1603,7 +1604,7 @@ type EnqueuedResponse struct {
|
|||
func (r *Repository) IsVaaEnqueued(
|
||||
ctx context.Context,
|
||||
chainID vaa.ChainID,
|
||||
emitter vaa.Address,
|
||||
emitter *types.Address,
|
||||
sequence string,
|
||||
) (bool, error) {
|
||||
|
||||
|
@ -1636,7 +1637,7 @@ func (r *Repository) IsVaaEnqueued(
|
|||
matchStage6 := bson.D{
|
||||
{"$match", bson.D{
|
||||
{"chainid", chainID},
|
||||
{"emitters.emitteraddress", fmt.Sprintf("0x%s", emitter.String())},
|
||||
{"emitters.emitteraddress", fmt.Sprintf("0x%s", emitter.ShortHex())},
|
||||
{"emitters.enqueuedvaas.sequence", sequence},
|
||||
}},
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/response"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -62,9 +63,16 @@ func (s *Service) FindGovernorStatus(ctx context.Context, p *pagination.Paginati
|
|||
}
|
||||
|
||||
// FindGovernorStatusByGuardianAddress get a governor status by guardianAddress.
|
||||
func (s *Service) FindGovernorStatusByGuardianAddress(ctx context.Context, guardianAddress string, p *pagination.Pagination) (*response.Response[*GovStatus], error) {
|
||||
func (s *Service) FindGovernorStatusByGuardianAddress(
|
||||
ctx context.Context,
|
||||
guardianAddress string,
|
||||
p *pagination.Pagination,
|
||||
) (*response.Response[*GovStatus], error) {
|
||||
|
||||
query := QueryGovernor().SetID(guardianAddress).SetPagination(p)
|
||||
|
||||
govStatus, err := s.repo.FindOneGovernorStatus(ctx, query)
|
||||
|
||||
res := response.Response[*GovStatus]{Data: govStatus}
|
||||
return &res, err
|
||||
}
|
||||
|
@ -182,7 +190,7 @@ func (s *Service) GetEnqueuedVaas(ctx context.Context) ([]*EnqueuedVaaItem, erro
|
|||
|
||||
// IsVaaEnqueued check vaa is enqueued.
|
||||
// Guardian api migration.
|
||||
func (s *Service) IsVaaEnqueued(ctx context.Context, chainID vaa.ChainID, emitter vaa.Address, seq string) (bool, error) {
|
||||
func (s *Service) IsVaaEnqueued(ctx context.Context, chainID vaa.ChainID, emitter *types.Address, seq string) (bool, error) {
|
||||
isEnqueued, err := s.repo.IsVaaEnqueued(ctx, chainID, emitter, seq)
|
||||
return isEnqueued, err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -32,19 +33,55 @@ func (s *Service) FindByChain(ctx context.Context, chain vaa.ChainID, p *paginat
|
|||
}
|
||||
|
||||
// FindByEmitter get all the observations by chainID and emitter address.
|
||||
func (s *Service) FindByEmitter(ctx context.Context, chain vaa.ChainID, emitter *vaa.Address, p *pagination.Pagination) ([]*ObservationDoc, error) {
|
||||
query := Query().SetChain(chain).SetEmitter(emitter.String()).SetPagination(p)
|
||||
func (s *Service) FindByEmitter(
|
||||
ctx context.Context,
|
||||
chain vaa.ChainID,
|
||||
emitter *types.Address,
|
||||
p *pagination.Pagination,
|
||||
) ([]*ObservationDoc, error) {
|
||||
|
||||
query := Query().
|
||||
SetChain(chain).
|
||||
SetEmitter(emitter.ShortHex()).
|
||||
SetPagination(p)
|
||||
|
||||
return s.repo.Find(ctx, query)
|
||||
}
|
||||
|
||||
// FindByVAA get all the observations for a VAA (chainID, emitter addrress and sequence number).
|
||||
func (s *Service) FindByVAA(ctx context.Context, chain vaa.ChainID, emitter *vaa.Address, seq string, p *pagination.Pagination) ([]*ObservationDoc, error) {
|
||||
query := Query().SetChain(chain).SetEmitter(emitter.String()).SetSequence(seq).SetPagination(p)
|
||||
func (s *Service) FindByVAA(
|
||||
ctx context.Context,
|
||||
chain vaa.ChainID,
|
||||
emitter *types.Address,
|
||||
seq string,
|
||||
p *pagination.Pagination,
|
||||
) ([]*ObservationDoc, error) {
|
||||
|
||||
query := Query().
|
||||
SetChain(chain).
|
||||
SetEmitter(emitter.ShortHex()).
|
||||
SetSequence(seq).
|
||||
SetPagination(p)
|
||||
|
||||
return s.repo.Find(ctx, query)
|
||||
}
|
||||
|
||||
// FindOne get a observation by chainID, emitter address, sequence, signer address and hash.
|
||||
func (s *Service) FindOne(ctx context.Context, chainID vaa.ChainID, emitterAddr *vaa.Address, seq string, signerAddr *vaa.Address, hash []byte) (*ObservationDoc, error) {
|
||||
query := Query().SetChain(chainID).SetEmitter(emitterAddr.String()).SetSequence(seq).SetGuardianAddr(signerAddr.String()).SetHash(hash)
|
||||
func (s *Service) FindOne(
|
||||
ctx context.Context,
|
||||
chainID vaa.ChainID,
|
||||
emitterAddr *types.Address,
|
||||
seq string,
|
||||
signerAddr *vaa.Address,
|
||||
hash []byte,
|
||||
) (*ObservationDoc, error) {
|
||||
|
||||
query := Query().
|
||||
SetChain(chainID).
|
||||
SetEmitter(emitterAddr.ShortHex()).
|
||||
SetSequence(seq).
|
||||
SetGuardianAddr(signerAddr.String()).
|
||||
SetHash(hash)
|
||||
|
||||
return s.repo.FindOne(ctx, query)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
errs "github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/internal/pagination"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/response"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -90,13 +91,13 @@ func (s *Service) FindByChain(
|
|||
func (s *Service) FindByEmitter(
|
||||
ctx context.Context,
|
||||
chain vaa.ChainID,
|
||||
emitter vaa.Address,
|
||||
emitter *types.Address,
|
||||
p *pagination.Pagination,
|
||||
) (*response.Response[[]*VaaDoc], error) {
|
||||
|
||||
query := Query().
|
||||
SetChain(chain).
|
||||
SetEmitter(emitter.String()).
|
||||
SetEmitter(emitter.ShortHex()).
|
||||
SetPagination(p)
|
||||
|
||||
vaas, err := s.repo.Find(ctx, query)
|
||||
|
@ -109,7 +110,7 @@ func (s *Service) FindByEmitter(
|
|||
func (s *Service) FindById(
|
||||
ctx context.Context,
|
||||
chain vaa.ChainID,
|
||||
emitter vaa.Address,
|
||||
emitter *types.Address,
|
||||
seq string,
|
||||
includeParsedPayload bool,
|
||||
) (*response.Response[*VaaDoc], error) {
|
||||
|
@ -141,24 +142,24 @@ func (s *Service) FindById(
|
|||
func (s *Service) findById(
|
||||
ctx context.Context,
|
||||
chain vaa.ChainID,
|
||||
emitter vaa.Address,
|
||||
emitter *types.Address,
|
||||
seq string,
|
||||
) (*VaaDoc, error) {
|
||||
|
||||
query := Query().
|
||||
SetChain(chain).
|
||||
SetEmitter(emitter.String()).
|
||||
SetEmitter(emitter.ShortHex()).
|
||||
SetSequence(seq)
|
||||
|
||||
return s.repo.FindOne(ctx, query)
|
||||
}
|
||||
|
||||
// findByIdWithPayload get a vaa with payload data by chainID, emitter address and sequence number.
|
||||
func (s *Service) findByIdWithPayload(ctx context.Context, chain vaa.ChainID, emitter vaa.Address, seq string) (*VaaDoc, error) {
|
||||
func (s *Service) findByIdWithPayload(ctx context.Context, chain vaa.ChainID, emitter *types.Address, seq string) (*VaaDoc, error) {
|
||||
|
||||
query := Query().
|
||||
SetChain(chain).
|
||||
SetEmitter(emitter.String()).
|
||||
SetEmitter(emitter.ShortHex()).
|
||||
SetSequence(seq)
|
||||
|
||||
vaas, err := s.repo.FindVaasWithPayload(ctx, query)
|
||||
|
@ -192,8 +193,8 @@ func (s *Service) GetVaaCount(ctx context.Context, p *pagination.Pagination) (*r
|
|||
// discardVaaNotIndexed discard a vaa request if the input sequence for a chainID, address is greatter than or equals
|
||||
// the cached value of the sequence for this chainID, address.
|
||||
// If the sequence does not exist we can not discard the request.
|
||||
func (s *Service) discardVaaNotIndexed(ctx context.Context, chain vaa.ChainID, emitter vaa.Address, seq string) bool {
|
||||
key := fmt.Sprintf("%s:%d:%s", "wormscan:vaa-max-sequence", chain, emitter.String())
|
||||
func (s *Service) discardVaaNotIndexed(ctx context.Context, chain vaa.ChainID, emitter *types.Address, seq string) bool {
|
||||
key := fmt.Sprintf("%s:%d:%s", "wormscan:vaa-max-sequence", chain, emitter.ShortHex())
|
||||
sequence, err := s.getCacheFunc(ctx, key)
|
||||
if err != nil {
|
||||
if errors.Is(err, errs.ErrInternalError) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/response"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -31,11 +32,11 @@ func ExtractChainID(c *fiber.Ctx, l *zap.Logger) (vaa.ChainID, error) {
|
|||
}
|
||||
|
||||
// ExtractEmitterAddr get emitter parameter from route path.
|
||||
func ExtractEmitterAddr(c *fiber.Ctx, l *zap.Logger) (*vaa.Address, error) {
|
||||
func ExtractEmitterAddr(c *fiber.Ctx, l *zap.Logger) (*types.Address, error) {
|
||||
|
||||
emitterStr := c.Params("emitter")
|
||||
|
||||
emitter, err := vaa.StringToAddress(emitterStr)
|
||||
emitter, err := types.StringToAddress(emitterStr)
|
||||
if err != nil {
|
||||
requestID := fmt.Sprintf("%v", c.Locals("requestid"))
|
||||
l.Error("failed to convert emitter to address",
|
||||
|
@ -46,7 +47,7 @@ func ExtractEmitterAddr(c *fiber.Ctx, l *zap.Logger) (*vaa.Address, error) {
|
|||
return nil, response.NewInvalidParamError(c, "MALFORMED EMITTER_ADDR", errors.WithStack(err))
|
||||
}
|
||||
|
||||
return &emitter, nil
|
||||
return emitter, nil
|
||||
}
|
||||
|
||||
// ExtractSequence get sequence parameter from route path.
|
||||
|
@ -69,37 +70,30 @@ func ExtractSequence(c *fiber.Ctx, l *zap.Logger) (uint64, error) {
|
|||
}
|
||||
|
||||
// ExtractGuardianAddress get guardian address from route path.
|
||||
func ExtractGuardianAddress(c *fiber.Ctx, l *zap.Logger) (string, error) {
|
||||
func ExtractGuardianAddress(c *fiber.Ctx, l *zap.Logger) (*types.Address, error) {
|
||||
|
||||
// read the address from query params
|
||||
tmp := c.Params("guardian_address")
|
||||
if tmp == "" {
|
||||
return "", response.NewInvalidParamError(c, "MALFORMED GUARDIAN ADDR", nil)
|
||||
return nil, response.NewInvalidParamError(c, "MALFORMED GUARDIAN ADDR", nil)
|
||||
}
|
||||
|
||||
// validate the address using the SDK
|
||||
guardianAddress, err := vaa.StringToAddress(tmp)
|
||||
// validate the address
|
||||
guardianAddress, err := types.StringToAddress(tmp)
|
||||
if err != nil {
|
||||
requestID := fmt.Sprintf("%v", c.Locals("requestid"))
|
||||
l.Error("failed to decode guardian address",
|
||||
zap.Error(err),
|
||||
zap.String("requestID", requestID),
|
||||
)
|
||||
return "", response.NewInvalidParamError(c, "MALFORMED GUARDIAN ADDR", errors.WithStack(err))
|
||||
return nil, response.NewInvalidParamError(c, "MALFORMED GUARDIAN ADDR", errors.WithStack(err))
|
||||
}
|
||||
|
||||
// make sure the address length is the expected
|
||||
addr := guardianAddress.String()
|
||||
if len(addr) != 64 {
|
||||
return "", response.NewInvalidParamError(c, "MALFORMED GUARDIAN ADDR", nil)
|
||||
}
|
||||
|
||||
// the address returned by the SDK has 24 leading zeroes
|
||||
return addr[24:], nil
|
||||
return guardianAddress, nil
|
||||
}
|
||||
|
||||
// ExtractVAAParams get VAA chain, address from route path.
|
||||
func ExtractVAAChainIDEmitter(c *fiber.Ctx, l *zap.Logger) (vaa.ChainID, *vaa.Address, error) {
|
||||
func ExtractVAAChainIDEmitter(c *fiber.Ctx, l *zap.Logger) (vaa.ChainID, *types.Address, error) {
|
||||
|
||||
chainID, err := ExtractChainID(c, l)
|
||||
if err != nil {
|
||||
|
@ -115,7 +109,7 @@ func ExtractVAAChainIDEmitter(c *fiber.Ctx, l *zap.Logger) (vaa.ChainID, *vaa.Ad
|
|||
}
|
||||
|
||||
// ExtractVAAParams get VAAA chain, address and sequence from route path.
|
||||
func ExtractVAAParams(c *fiber.Ctx, l *zap.Logger) (vaa.ChainID, *vaa.Address, uint64, error) {
|
||||
func ExtractVAAParams(c *fiber.Ctx, l *zap.Logger) (vaa.ChainID, *types.Address, uint64, error) {
|
||||
|
||||
chainID, err := ExtractChainID(c, l)
|
||||
if err != nil {
|
||||
|
|
|
@ -139,7 +139,7 @@ func (c *Controller) IsVaaEnqueued(ctx *fiber.Ctx) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isEnqueued, err := c.srv.IsVaaEnqueued(ctx.Context(), chainID, *emitter, strconv.FormatUint(seq, 10))
|
||||
isEnqueued, err := c.srv.IsVaaEnqueued(ctx.Context(), chainID, emitter, strconv.FormatUint(seq, 10))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func (c *Controller) FindSignedVAAByID(ctx *fiber.Ctx) error {
|
|||
vaa, err := c.srv.FindById(
|
||||
ctx.Context(),
|
||||
chainID,
|
||||
*emitter,
|
||||
emitter,
|
||||
strconv.FormatUint(seq, 10),
|
||||
false, /*includeParsedPayload*/
|
||||
)
|
||||
|
|
|
@ -65,7 +65,7 @@ func (c *Controller) FindGovernorConfigurationByGuardianAddress(ctx *fiber.Ctx)
|
|||
}
|
||||
|
||||
// query the database
|
||||
govConfigs, err := c.srv.FindGovernorConfigByGuardianAddress(ctx.Context(), guardianAddress)
|
||||
govConfigs, err := c.srv.FindGovernorConfigByGuardianAddress(ctx.Context(), guardianAddress.ShortHex())
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(govConfigs) == 0 {
|
||||
|
@ -127,7 +127,7 @@ func (c *Controller) FindGovernorStatusByGuardianAddress(ctx *fiber.Ctx) error {
|
|||
return err
|
||||
}
|
||||
|
||||
govStatus, err := c.srv.FindGovernorStatusByGuardianAddress(ctx.Context(), guardianAddress, p)
|
||||
govStatus, err := c.srv.FindGovernorStatusByGuardianAddress(ctx.Context(), guardianAddress.ShortHex(), p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ func (c *Controller) FindByEmitter(ctx *fiber.Ctx) error {
|
|||
return err
|
||||
}
|
||||
|
||||
vaas, err := c.srv.FindByEmitter(ctx.Context(), chainID, *emitter, p)
|
||||
vaas, err := c.srv.FindByEmitter(ctx.Context(), chainID, emitter, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func (c *Controller) FindById(ctx *fiber.Ctx) error {
|
|||
vaa, err := c.srv.FindById(
|
||||
ctx.Context(),
|
||||
chainID,
|
||||
*emitter,
|
||||
emitter,
|
||||
strconv.FormatUint(seq, 10),
|
||||
includeParsedPayload,
|
||||
)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/wormhole-foundation/wormhole-explorer/api/handlers/heartbeats"
|
||||
vaaservice "github.com/wormhole-foundation/wormhole-explorer/api/handlers/vaa"
|
||||
errs "github.com/wormhole-foundation/wormhole-explorer/api/internal/errors"
|
||||
"github.com/wormhole-foundation/wormhole-explorer/api/types"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
@ -51,14 +52,16 @@ func (h *Handler) GetSignedVAA(ctx context.Context, request *publicrpcv1.GetSign
|
|||
|
||||
address, err := hex.DecodeString(request.MessageId.EmitterAddress)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to decode address: %v", err))
|
||||
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to decode address from hex: %v", err))
|
||||
}
|
||||
if len(address) != 32 {
|
||||
return nil, status.Error(codes.InvalidArgument, "address must be 32 bytes")
|
||||
}
|
||||
|
||||
addr := vaa.Address{}
|
||||
copy(addr[:], address)
|
||||
addr, err := types.BytesToAddress(address)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to decode address from bytes: %v", err))
|
||||
}
|
||||
|
||||
sequence := strconv.FormatUint(request.MessageId.Sequence, 10)
|
||||
|
||||
|
@ -222,7 +225,7 @@ func (h *Handler) GovernorIsVAAEnqueued(ctx context.Context, request *publicrpcv
|
|||
return nil, status.Error(codes.InvalidArgument, "Parameters are required")
|
||||
}
|
||||
chainID := vaa.ChainID(request.MessageId.EmitterChain)
|
||||
emitterAddress, err := vaa.StringToAddress(request.MessageId.EmitterAddress)
|
||||
emitterAddress, err := types.StringToAddress(request.MessageId.EmitterAddress)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Invalid emitter address")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
)
|
||||
|
||||
type Address struct {
|
||||
address vaa.Address
|
||||
}
|
||||
|
||||
func BytesToAddress(b []byte) (*Address, error) {
|
||||
|
||||
var a Address
|
||||
|
||||
if len(b) != len(a.address) {
|
||||
return nil, fmt.Errorf("expected byte slice to have len=%d, but got %d instead", len(a.address), len(b))
|
||||
}
|
||||
|
||||
copy(a.address[:], b)
|
||||
|
||||
return &a, nil
|
||||
}
|
||||
|
||||
// StringToAddress converts a hex-encoded address string into an *Address.
|
||||
func StringToAddress(s string) (*Address, error) {
|
||||
|
||||
a, err := vaa.StringToAddress(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Address{address: a}, nil
|
||||
}
|
||||
|
||||
// Hex returns the full 32-byte address, encoded as hex.
|
||||
func (addr *Address) Hex() string {
|
||||
return addr.address.String()
|
||||
}
|
||||
|
||||
// ShortHex returns a hex-encoded address that is usually shorted than Hex().
|
||||
//
|
||||
// If the full address returned by Hex() is prefixed 12 bytes set to zero,
|
||||
// this function will trim those bytes.
|
||||
func (addr *Address) ShortHex() string {
|
||||
|
||||
full := addr.Hex()
|
||||
|
||||
if len(full) == 64 && strings.HasPrefix(full, "000000000000000000000000") {
|
||||
return full[24:]
|
||||
}
|
||||
|
||||
return full
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package types
|
||||
|
||||
import "testing"
|
||||
|
||||
// Test_Address_ShortString runs several test cases on the method `Address.ShortString()`.
|
||||
func Test_Address_ShortString(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
Input string
|
||||
Hex string
|
||||
ShortHex string
|
||||
}{
|
||||
{
|
||||
Input: "0x000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
Hex: "000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
ShortHex: "f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
},
|
||||
{
|
||||
Input: "000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
Hex: "000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
ShortHex: "f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
},
|
||||
{
|
||||
Input: "0xf890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
Hex: "000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
ShortHex: "f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
},
|
||||
{
|
||||
Input: "f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
Hex: "000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
ShortHex: "f890982f9310df57d00f659cf4fd87e65aded8d7",
|
||||
},
|
||||
{
|
||||
Input: "ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
|
||||
Hex: "ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
|
||||
ShortHex: "ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
|
||||
},
|
||||
{
|
||||
Input: "0xec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
|
||||
Hex: "ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
|
||||
ShortHex: "ec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
tc := &testCases[i]
|
||||
|
||||
addr, err := StringToAddress(tc.Input)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse address %s: %v", tc.Input, err)
|
||||
}
|
||||
|
||||
if addr.Hex() != tc.Hex {
|
||||
t.Fatalf("expected Address.Hex()=%s, but got %s", tc.Hex, addr.Hex())
|
||||
}
|
||||
|
||||
if addr.ShortHex() != tc.ShortHex {
|
||||
t.Fatalf("expected Address.ShortHex()=%s, but got %s", tc.ShortHex, addr.ShortHex())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue