wormhole/node/pkg/accountant/query_test.go

235 lines
9.0 KiB
Go

package accountant
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"reflect"
"testing"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
cosmossdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
)
func TestParseMissingObservationsResponse(t *testing.T) {
responsesJson := []byte("{\"missing\":[{\"chain_id\":2,\"tx_hash\":\"y1E+jwgozWKEVbHt9dIeErgNXlHnntQwdzymYSCmBEA=\"},{\"chain_id\":4,\"tx_hash\":\"FZyF7xR5bIwtvdBIlIrDEZc+mrCkN/ixjGazgJdJdQQ=\"}]}")
var response MissingObservationsResponse
err := json.Unmarshal(responsesJson, &response)
require.NoError(t, err)
require.Equal(t, 2, len(response.Missing))
expectedTxHash0, err := hex.DecodeString("cb513e8f0828cd628455b1edf5d21e12b80d5e51e79ed430773ca66120a60440")
require.NoError(t, err)
expectedTxHash1, err := hex.DecodeString("159c85ef14796c8c2dbdd048948ac311973e9ab0a437f8b18c66b38097497504")
require.NoError(t, err)
expectedResult := MissingObservationsResponse{
Missing: []MissingObservation{
MissingObservation{
ChainId: uint16(vaa.ChainIDEthereum),
TxHash: expectedTxHash0,
},
MissingObservation{
ChainId: uint16(vaa.ChainIDBSC),
TxHash: expectedTxHash1,
},
},
}
assert.Equal(t, expectedResult, response)
}
func TestParseBatchTransferStatusCommittedResponse(t *testing.T) {
responsesJson := []byte("{\"details\":[{\"key\":{\"emitter_chain\":2,\"emitter_address\":\"0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16\",\"sequence\":1674568234},\"status\":{\"committed\":{\"data\":{\"amount\":\"1000000000000000000\",\"token_chain\":2,\"token_address\":\"0000000000000000000000002d8be6bf0baa74e0a907016679cae9190e80dd0a\",\"recipient_chain\":4},\"digest\":\"1nbbff/7/ai9GJUs4h2JymFuO4+XcasC6t05glXc99M=\"}}}]}")
var response BatchTransferStatusResponse
err := json.Unmarshal(responsesJson, &response)
require.NoError(t, err)
require.Equal(t, 1, len(response.Details))
expectedEmitterAddress, err := vaa.StringToAddress("0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16")
require.NoError(t, err)
expectedTokenAddress, err := vaa.StringToAddress("0000000000000000000000002d8be6bf0baa74e0a907016679cae9190e80dd0a")
require.NoError(t, err)
expectedAmount := cosmossdk.NewInt(1000000000000000000)
expectedDigest, err := hex.DecodeString("d676db7dfffbfda8bd18952ce21d89ca616e3b8f9771ab02eadd398255dcf7d3")
require.NoError(t, err)
expectedResult := TransferDetails{
Key: TransferKey{
EmitterChain: uint16(vaa.ChainIDEthereum),
EmitterAddress: expectedEmitterAddress,
Sequence: 1674568234,
},
Status: &TransferStatus{
Committed: &TransferStatusCommitted{
Data: TransferData{
Amount: &expectedAmount,
TokenChain: uint16(vaa.ChainIDEthereum),
TokenAddress: expectedTokenAddress,
RecipientChain: uint16(vaa.ChainIDBSC),
},
Digest: expectedDigest,
},
},
}
// Use DeepEqual() because the response contains pointers.
assert.True(t, reflect.DeepEqual(expectedResult, response.Details[0]))
}
func TestParseBatchTransferStatusNotFoundResponse(t *testing.T) {
responsesJson := []byte("{\"details\":[{\"key\":{\"emitter_chain\":2,\"emitter_address\":\"0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16\",\"sequence\":1674484597},\"status\":null}]}")
var response BatchTransferStatusResponse
err := json.Unmarshal(responsesJson, &response)
require.NoError(t, err)
require.Equal(t, 1, len(response.Details))
expectedEmitterAddress, err := vaa.StringToAddress("0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16")
require.NoError(t, err)
expectedResult := TransferDetails{
Key: TransferKey{
EmitterChain: uint16(vaa.ChainIDEthereum),
EmitterAddress: expectedEmitterAddress,
Sequence: 1674484597,
},
Status: nil,
}
// Use DeepEqual() because the response contains pointers.
assert.True(t, reflect.DeepEqual(expectedResult, response.Details[0]))
}
func TestParseBatchTransferStatusPendingResponse(t *testing.T) {
responsesJson := []byte("{\"details\":[{\"key\":{\"emitter_chain\":2,\"emitter_address\":\"0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16\",\"sequence\":3},\"status\":{\"pending\":[{\"digest\":\"65hmAN4IbW9MBnSDzYmgoD/3ze+F8ik9NGeKR/vQ4J4=\",\"tx_hash\":\"CjHx8zExnr4JU8ewAu5/tXM6a5QyslKufGHZNSr0aE8=\",\"signatures\":\"1\",\"guardian_set_index\":0,\"emitter_chain\":2}]}}]}")
var response BatchTransferStatusResponse
err := json.Unmarshal(responsesJson, &response)
require.NoError(t, err)
require.Equal(t, 1, len(response.Details))
expectedEmitterAddress, err := vaa.StringToAddress("0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16")
require.NoError(t, err)
expectedDigest, err := hex.DecodeString("eb986600de086d6f4c067483cd89a0a03ff7cdef85f2293d34678a47fbd0e09e")
require.NoError(t, err)
expectedTxHash, err := hex.DecodeString("0a31f1f331319ebe0953c7b002ee7fb5733a6b9432b252ae7c61d9352af4684f")
require.NoError(t, err)
expectedResult := TransferDetails{
Key: TransferKey{
EmitterChain: uint16(vaa.ChainIDEthereum),
EmitterAddress: expectedEmitterAddress,
Sequence: 3,
},
Status: &TransferStatus{
Pending: &[]TransferStatusPending{
TransferStatusPending{
Digest: expectedDigest,
TxHash: expectedTxHash,
Signatures: "1",
GuardianSetIndex: 0,
EmitterChain: uint16(vaa.ChainIDEthereum),
},
},
},
}
// Use DeepEqual() because the response contains pointers.
assert.True(t, reflect.DeepEqual(expectedResult, response.Details[0]))
}
// BatchTransferStatusQueryConnMock allows us to mock batch_transfer_status by implementing SubmitQuery.
type BatchTransferStatusQueryConnMock struct {
resp []byte
}
func (qc *BatchTransferStatusQueryConnMock) SubmitQuery(ctx context.Context, contractAddress string, query []byte) ([]byte, error) {
// Force a failure if the query is much bigger than what we are allowing. This does not have to be exact, since the chunking tests will be using a lot more than that.
// A json encoded transfer key is about 150 characters.
if len(query) > 150*maxPendingsPerQuery+1000 {
return []byte{}, errors.New("query too large")
}
return qc.resp, nil
}
// validateBatchTransferStatusResults makes sure the query returned everything expected, and nothing extra.
func validateBatchTransferStatusResults(t *testing.T, keys []TransferKey, transferDetails map[string]*TransferStatus) {
for _, key := range keys {
tKey := key.String()
_, exists := transferDetails[tKey]
require.Equal(t, true, exists)
delete(transferDetails, tKey)
}
require.Equal(t, 0, len(transferDetails))
}
func TestBatchTransferStatusForExactlyOneTransfer(t *testing.T) {
ctx := context.Background()
logger := zap.NewNop()
keys, queryResp := createTransferKeysForTestingBatchTransferStatus(t, 1)
require.Equal(t, 1, len(keys))
qc := &BatchTransferStatusQueryConnMock{resp: queryResp}
transferDetails, err := queryBatchTransferStatusWithConn(ctx, logger, qc, "wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465", keys)
require.NoError(t, err)
require.Equal(t, len(keys), len(transferDetails))
validateBatchTransferStatusResults(t, keys, transferDetails)
}
func TestBatchTransferStatusForExactlyOneChunk(t *testing.T) {
ctx := context.Background()
logger := zap.NewNop()
keys, queryResp := createTransferKeysForTestingBatchTransferStatus(t, maxPendingsPerQuery)
require.Equal(t, maxPendingsPerQuery, len(keys))
qc := &BatchTransferStatusQueryConnMock{resp: queryResp}
transferDetails, err := queryBatchTransferStatusWithConn(ctx, logger, qc, "wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465", keys)
require.NoError(t, err)
require.Equal(t, len(keys), len(transferDetails))
validateBatchTransferStatusResults(t, keys, transferDetails)
}
func TestBatchTransferStatusForExactlyOneChunkPlus1(t *testing.T) {
ctx := context.Background()
logger := zap.NewNop()
keys, queryResp := createTransferKeysForTestingBatchTransferStatus(t, maxPendingsPerQuery+1)
require.Equal(t, maxPendingsPerQuery+1, len(keys))
qc := &BatchTransferStatusQueryConnMock{resp: queryResp}
transferDetails, err := queryBatchTransferStatusWithConn(ctx, logger, qc, "wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465", keys)
require.NoError(t, err)
require.Equal(t, len(keys), len(transferDetails))
validateBatchTransferStatusResults(t, keys, transferDetails)
}
func TestBatchTransferStatusMultipleChunks(t *testing.T) {
ctx := context.Background()
logger := zap.NewNop()
keys, queryResp := createTransferKeysForTestingBatchTransferStatus(t, -1)
require.Less(t, maxPendingsPerQuery, len(keys))
qc := &BatchTransferStatusQueryConnMock{resp: queryResp}
transferDetails, err := queryBatchTransferStatusWithConn(ctx, logger, qc, "wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465", keys)
require.NoError(t, err)
require.Equal(t, len(keys), len(transferDetails))
validateBatchTransferStatusResults(t, keys, transferDetails)
}