The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/rosetta/services/operation_components_test.go

609 lines
16 KiB

Rosetta Implementation - pt4 (Stage 3.4 of Node API Overhaul) (#3380) * [rosetta] Add /construct function framework Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add network ID check to all construct endpoints Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add UnsupportedCurveTypeError Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Implement ConstructionDerive & add ConstructAPI router Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Make recover middleware the outermost middleware Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Correct error for block not found Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rpc] Expose EstimateGas Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add InvalidTransactionConstructionError * Add GetValidConstructionOperations Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Make TransactionMetadata optional ptr * Add UnmarshalFromInterface for TransactionMetadata Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add InvalidTransactionConstructionError to network response Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add ConstructionPreprocess & ConstructionMetadata skeleton * Add Helper methods for said functions Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add GasPrice to ConstructMetadata Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Make suggested gas fee & price its own fn Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Nit - fix comment Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add To & From Account ID in tx metadata * remove getAmountFromUndelegateMessage * make contract address a valid account identifier * remove needless metadata in non-staking operations Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add error report for b32 error in newAccountIdentifier Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Simplify assertValidNetworkIdentifier Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Use sdk MapMarshall instead of rpc structured response * remove unused GetValidConstructionOperations * Add CurrencyHash Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Implement assertValidTransferOperationsAndGetTxAccounts * refactor usages of rpc structured response for sdk map marshall * add account identifier checks for transaction metadata Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Max related operation check more general for tx op check * refactor names for readability Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add & Expose OperationComponents * Remove txAccounts & add OperationComponents to metadata for quicker processing * Remove From & To acc ID from TransactionMetadata as it's in OperationComponents * Update tests for changes Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add tx type to OperationComponents Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add logs to TransactionMetadata * Enforce Operation type uniqueness invariant for each transaction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add error for 3+ operations in getOperationComponents Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Expose GetOperationComponents Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add CrossShardTransactionOperationMetadata Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add staking operation medata type declaration Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Fix error messages & update comment Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Implement getCrossShardOperationComponents * rename txAccs to components for clarity Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Implement getContractCreationOperationComponents * Fix some edge case optional checks for operation validation Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [go.mod] Bump rosetta version to 0.4.4 & dependent libs * Update broken rosetta structs Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add ChainID to ConstructMetadata Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Rename PreStakingBlockRewardOperation Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Init operation_components.go & move respective code Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Refactor formatTransaction for clarity Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Move maxNumOfConstructionOps to operation_components.go * Clarify unsupported type err msg Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Implement framework for ConstructionPayloads * Remove currying OperationComponents in metadata as PublicKeys is now part of the request in the necessary endpoints * Add respective checks for added PublicKeys * Make getAddressFromPublicKey more general & update tests Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add getAddress and update respective functions Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Create transaction_construction.go & impl ConstructTransaction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add unmarshal check for ConstructMetadata & ConstructMetadataOptions * Remove constructTransaction * Wrap unsigned transaction with UnsignedTransaction to include intended signer * Add framework for ConstructionParse Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add getSigningPayload method to construction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [internal/commonm] Add MustGeneratePrivateKey Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Implement parseUnsignedTransaction * Add unpackWrappedTransactionFromHexString & refactor rlp encoding of transactions * Make getSigningPayload return a list Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add TestUnpackWrappedTransactionFromHexString Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Implement parseSignedTransaction * Move unpackWrappedTransactionFromHexString to ConstructionParse before parsing transactions bases on if it's signed or not Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Nit - fix WrappedTransaction comments Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add extra negative tests for unpackWrappedTransactionFromHexString Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Finish initial Construct implementation * Implement ConstructionCombine * Implement ConstructionHash * Implement ConstructionSubmit * Ensure RLPbytes & From is present in WrappedTransaction when unpackWrappedTransactionFromHexString is called Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Refactor construction into separate files * Move tests into appropriate files Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Implement construction_check_test.go * Update edge case for getSuggestedFeeAndPrice found during testing Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Implement construction_parse_test.go * Clarify names for construction_create_test.go Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Fix ConstructionParse to not use crypto.PubkeyToAddress Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Fix UnmarshalFromInterface for CrossShardTransactionOperationMetadata Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add operation_components_test.go * Implement TestGetContractCreationOperationComponents * Implement TestGetCrossShardOperationComponents Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Finish operation_components_test.go * Implement TestGetTransferOperationComponents * Implement TestGetOperationComponents Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Fix big number checks for getTransferOperationComponents Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Implement transaction_construction_test.go * Implement TestConstructPlainTransaction * Implement TestConstructCrossShardTransaction * Implement TestConstructContractCreationTransaction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add shard ID checks for constructCrossShardTransaction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add bad curve test for TestGetAddressFromPublicKey Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add nil error catches for Construction API * Fix nits in messages as seen during pass * Add DefaultGasLimit Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add trace message with version to all err msgs * Add NewError unit test Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add TestGetAddressFromKnownPublicKey Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [hmy] Fix possible nil ptr crash for GetBlockSigners Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Edge case bug fixes * Create empty TransactionMetdata if no metadata is provided in operations. Also update tests to correctly account for the behavior. * In pre-staking era make current block one less than the absolute latest to guarentee calculation of pres-taking eara block rewards. Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Fix unpackWrappedTransactionFromHexString * Rename function to unpackWrappedTransactionFromString * Update respective tests Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Make parsed transaction statuses empty Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Remove needles list initialization Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add SignatureType & SignedPayloadLength with checks Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Fix genesis network status crash Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Correct error message dumps for transaction_construction.go Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add OperationType to ConstructMetadataOptions Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Fix rosetta service rebase Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rpc] Fix estimate gas fail check Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add formatNegativeValue to ensure there's only 1 zero * Correct regression found in constructCrossShardTransaction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> [rosetta] Add contract creation estimate gas hack Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add DefaultSenderAddress for transaction formatter * Update Construction API parser to reflect change Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Fix imports Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Address PR comments * Add GetCallStackInfo to internal utils * Add EstimateGas TODO in RPC package * Remove DefaultGasLimit to use param gas limit Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Add checks to tx formatter for nil to addr * Remove needless block check for genesisBlock Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu> * [rosetta] Remove EstimatedGasUsed from WrappedTransaction Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>
4 years ago
package services
import (
"math/big"
"testing"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/ethereum/go-ethereum/crypto"
internalCommon "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/rosetta/common"
)
func TestGetContractCreationOperationComponents(t *testing.T) {
refAmount := &types.Amount{
Value: "-12000",
Currency: &common.Currency,
}
refKey := internalCommon.MustGeneratePrivateKey()
refFrom, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
// test valid operations
refOperation := &types.Operation{
Type: common.ContractCreationOperation,
Amount: refAmount,
Account: refFrom,
}
testComponents, rosettaError := getContractCreationOperationComponents(refOperation)
if rosettaError != nil {
t.Error(rosettaError)
}
if testComponents.Type != refOperation.Type {
t.Error("expected same operation")
}
if testComponents.From == nil || types.Hash(testComponents.From) != types.Hash(refFrom) {
t.Error("expect same sender")
}
if testComponents.Amount.Cmp(big.NewInt(12000)) != 0 {
t.Error("expected amount to be absolute value of reference amount")
}
// test nil amount
_, rosettaError = getContractCreationOperationComponents(&types.Operation{
Type: common.ContractCreationOperation,
Amount: nil,
Account: refFrom,
})
if rosettaError == nil {
t.Error("expected error")
}
// test positive amount
_, rosettaError = getContractCreationOperationComponents(&types.Operation{
Type: common.ContractCreationOperation,
Amount: &types.Amount{
Value: "12000",
Currency: &common.Currency,
},
Account: refFrom,
})
if rosettaError == nil {
t.Error("expected error")
}
// test different/unsupported currency
_, rosettaError = getContractCreationOperationComponents(&types.Operation{
Type: common.ContractCreationOperation,
Amount: &types.Amount{
Value: "-12000",
Currency: &types.Currency{
Symbol: "bad",
Decimals: 9,
},
},
Account: refFrom,
})
if rosettaError == nil {
t.Error("expected error")
}
// test nil account
_, rosettaError = getContractCreationOperationComponents(&types.Operation{
Type: common.ContractCreationOperation,
Amount: refAmount,
Account: nil,
})
if rosettaError == nil {
t.Error("expected error")
}
// test nil operation
_, rosettaError = getContractCreationOperationComponents(nil)
if rosettaError == nil {
t.Error("expected error")
}
}
func TestGetCrossShardOperationComponents(t *testing.T) {
refAmount := &types.Amount{
Value: "-12000",
Currency: &common.Currency,
}
refFromKey := internalCommon.MustGeneratePrivateKey()
refFrom, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refFromKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
refToKey := internalCommon.MustGeneratePrivateKey()
refTo, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refToKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
refMetadata := common.CrossShardTransactionOperationMetadata{
From: refFrom,
To: refTo,
}
refMetadataMap, err := types.MarshalMap(refMetadata)
if err != nil {
t.Fatal(err)
}
// test valid operations
refOperation := &types.Operation{
Type: common.CrossShardTransferOperation,
Amount: refAmount,
Account: refFrom,
Metadata: refMetadataMap,
}
testComponents, rosettaError := getCrossShardOperationComponents(refOperation)
if rosettaError != nil {
t.Fatal(rosettaError)
}
if testComponents.Type != refOperation.Type {
t.Error("expected same operation")
}
if testComponents.From == nil || types.Hash(testComponents.From) != types.Hash(refFrom) {
t.Error("expect same sender")
}
if testComponents.To == nil || types.Hash(testComponents.To) != types.Hash(refTo) {
t.Error("expected same sender")
}
if testComponents.Amount.Cmp(big.NewInt(12000)) != 0 {
t.Error("expected amount to be absolute value of reference amount")
}
// test nil amount
_, rosettaError = getCrossShardOperationComponents(&types.Operation{
Type: common.CrossShardTransferOperation,
Amount: nil,
Account: refFrom,
Metadata: refMetadataMap,
})
if rosettaError == nil {
t.Error("expected error")
}
// test positive amount
_, rosettaError = getCrossShardOperationComponents(&types.Operation{
Type: common.CrossShardTransferOperation,
Amount: &types.Amount{
Value: "12000",
Currency: &common.Currency,
},
Account: refFrom,
Metadata: refMetadataMap,
})
if rosettaError == nil {
t.Error("expected error")
}
// test different/unsupported currency
_, rosettaError = getCrossShardOperationComponents(&types.Operation{
Type: common.CrossShardTransferOperation,
Amount: &types.Amount{
Value: "-12000",
Currency: &types.Currency{
Symbol: "bad",
Decimals: 9,
},
},
Account: refFrom,
Metadata: refMetadataMap,
})
if rosettaError == nil {
t.Error("expected error")
}
// test nil account
_, rosettaError = getCrossShardOperationComponents(&types.Operation{
Type: common.CrossShardTransferOperation,
Amount: refAmount,
Account: nil,
Metadata: refMetadataMap,
})
if rosettaError == nil {
t.Error("expected error")
}
// test no metadata
_, rosettaError = getCrossShardOperationComponents(&types.Operation{
Type: common.CrossShardTransferOperation,
Amount: refAmount,
Account: refFrom,
})
if rosettaError == nil {
t.Error("expected error")
}
// test bad metadata
randomKey := internalCommon.MustGeneratePrivateKey()
randomID, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(randomKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
badMetadata := common.CrossShardTransactionOperationMetadata{
From: randomID,
To: refTo,
}
badMetadataMap, err := types.MarshalMap(badMetadata)
if err != nil {
t.Fatal(err)
}
_, rosettaError = getCrossShardOperationComponents(&types.Operation{
Type: common.CrossShardTransferOperation,
Amount: refAmount,
Account: refFrom,
Metadata: badMetadataMap,
})
if rosettaError == nil {
t.Error("expected error")
}
// test nil operation
_, rosettaError = getCrossShardOperationComponents(nil)
if rosettaError == nil {
t.Error("expected error")
}
}
func TestGetTransferOperationComponents(t *testing.T) {
refFromAmount := &types.Amount{
Value: "-12000",
Currency: &common.Currency,
}
refToAmount := &types.Amount{
Value: "12000",
Currency: &common.Currency,
}
refFromKey := internalCommon.MustGeneratePrivateKey()
refFrom, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refFromKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
refToKey := internalCommon.MustGeneratePrivateKey()
refTo, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refToKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
// test valid operations
refOperations := []*types.Operation{
{
OperationIdentifier: &types.OperationIdentifier{
Index: 0,
},
Type: common.TransferOperation,
Amount: refFromAmount,
Account: refFrom,
},
{
OperationIdentifier: &types.OperationIdentifier{
Index: 1,
},
RelatedOperations: []*types.OperationIdentifier{
{
Index: 0,
},
},
Type: common.TransferOperation,
Amount: refToAmount,
Account: refTo,
},
}
testComponents, rosettaError := getTransferOperationComponents(refOperations)
if rosettaError != nil {
t.Fatal(rosettaError)
}
if testComponents.Type != refOperations[0].Type {
t.Error("expected same operation")
}
if testComponents.From == nil || types.Hash(testComponents.From) != types.Hash(refFrom) {
t.Error("expect same sender")
}
if testComponents.To == nil || types.Hash(testComponents.To) != types.Hash(refTo) {
t.Error("expected same sender")
}
if testComponents.Amount.Cmp(big.NewInt(12000)) != 0 {
t.Error("expected amount to be absolute value of reference amount")
}
// test valid operations flipped
refOperations[0].Amount = refToAmount
refOperations[0].Account = refTo
refOperations[1].Amount = refFromAmount
refOperations[1].Account = refFrom
testComponents, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError != nil {
t.Fatal(rosettaError)
}
if testComponents.Type != refOperations[0].Type {
t.Error("expected same operation")
}
if testComponents.From == nil || types.Hash(testComponents.From) != types.Hash(refFrom) {
t.Error("expect same sender")
}
if testComponents.To == nil || types.Hash(testComponents.To) != types.Hash(refTo) {
t.Error("expected same sender")
}
if testComponents.Amount.Cmp(big.NewInt(12000)) != 0 {
t.Error("expected amount to be absolute value of reference amount")
}
// test no sender
refOperations[0].Amount = refFromAmount
refOperations[0].Account = nil
refOperations[1].Amount = refToAmount
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test no receiver
refOperations[0].Amount = refFromAmount
refOperations[0].Account = refFrom
refOperations[1].Amount = refToAmount
refOperations[1].Account = nil
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test invalid operation
refOperations[0].Type = common.ExpendGasOperation
refOperations[1].Type = common.TransferOperation
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test invalid operation sender
refOperations[0].Type = common.TransferOperation
refOperations[1].Type = common.ExpendGasOperation
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
refOperations[1].Type = common.TransferOperation
// test nil amount
refOperations[0].Amount = nil
refOperations[0].Account = refFrom
refOperations[1].Amount = refToAmount
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test nil amount sender
refOperations[0].Amount = refFromAmount
refOperations[0].Account = refFrom
refOperations[1].Amount = nil
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test uneven amount
refOperations[0].Amount = refFromAmount
refOperations[0].Account = refFrom
refOperations[1].Amount = &types.Amount{
Value: "0",
Currency: &common.Currency,
}
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test uneven amount sender
refOperations[0].Amount = &types.Amount{
Value: "0",
Currency: &common.Currency,
}
refOperations[0].Account = refFrom
refOperations[1].Amount = refToAmount
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test nil amount
refOperations[0].Amount = refFromAmount
refOperations[0].Account = refFrom
refOperations[1].Amount = nil
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test nil amount sender
refOperations[0].Amount = nil
refOperations[0].Account = refFrom
refOperations[1].Amount = refToAmount
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test invalid currency
refOperations[0].Amount = refFromAmount
refOperations[0].Amount.Currency = &types.Currency{
Symbol: "bad",
Decimals: 9,
}
refOperations[0].Account = refFrom
refOperations[1].Amount = refToAmount
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
refOperations[0].Amount.Currency = &common.Currency
// test invalid currency sender
refOperations[0].Amount = refFromAmount
refOperations[0].Account = refFrom
refOperations[1].Amount = refToAmount
refOperations[1].Amount.Currency = &types.Currency{
Symbol: "bad",
Decimals: 9,
}
refOperations[1].Account = refTo
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
refOperations[1].Amount.Currency = &common.Currency
// test invalid related operation
refOperations[1].RelatedOperations[0].Index = 2
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
refOperations[1].RelatedOperations[0].Index = 0
// test cyclic related operation
refOperations[0].RelatedOperations = []*types.OperationIdentifier{
{
Index: 1,
},
}
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// Test invalid related operation sender
refOperations[1].RelatedOperations = nil
refOperations[0].RelatedOperations[0].Index = 3
_, rosettaError = getTransferOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// Test nil operations
_, rosettaError = getTransferOperationComponents(nil)
if rosettaError == nil {
t.Error("expected error")
}
}
func TestGetOperationComponents(t *testing.T) {
refFromAmount := &types.Amount{
Value: "-12000",
Currency: &common.Currency,
}
refToAmount := &types.Amount{
Value: "12000",
Currency: &common.Currency,
}
refFromKey := internalCommon.MustGeneratePrivateKey()
refFrom, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refFromKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
refToKey := internalCommon.MustGeneratePrivateKey()
refTo, rosettaError := newAccountIdentifier(crypto.PubkeyToAddress(refToKey.PublicKey))
if rosettaError != nil {
t.Fatal(rosettaError)
}
// test valid transaction operation
// Detailed test in TestGetTransferOperationComponents
_, rosettaError = GetOperationComponents([]*types.Operation{
{
OperationIdentifier: &types.OperationIdentifier{
Index: 0,
},
Type: common.TransferOperation,
Amount: refFromAmount,
Account: refFrom,
},
{
OperationIdentifier: &types.OperationIdentifier{
Index: 1,
},
RelatedOperations: []*types.OperationIdentifier{
{
Index: 0,
},
},
Type: common.TransferOperation,
Amount: refToAmount,
Account: refTo,
},
})
if rosettaError != nil {
t.Error(rosettaError)
}
// test valid cross-shard transaction operation
// Detailed test in TestGetCrossShardOperationComponents
refMetadata := common.CrossShardTransactionOperationMetadata{
From: refFrom,
To: refTo,
}
refMetadataMap, err := types.MarshalMap(refMetadata)
if err != nil {
t.Fatal(err)
}
_, rosettaError = GetOperationComponents([]*types.Operation{
{
Type: common.CrossShardTransferOperation,
Amount: refFromAmount,
Account: refFrom,
Metadata: refMetadataMap,
},
})
if rosettaError != nil {
t.Error(rosettaError)
}
// test valid contract creation operation
// Detailed test in TestGetContractCreationOperationComponents
_, rosettaError = GetOperationComponents([]*types.Operation{
{
Type: common.ContractCreationOperation,
Amount: refFromAmount,
Account: refFrom,
},
})
if rosettaError != nil {
t.Error(rosettaError)
}
// test invalid number of operations
refOperations := []*types.Operation{}
_, rosettaError = GetOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test invalid number of operations pas max number of operations
for i := 0; i <= maxNumOfConstructionOps+1; i++ {
refOperations = append(refOperations, &types.Operation{})
}
_, rosettaError = GetOperationComponents(refOperations)
if rosettaError == nil {
t.Error("expected error")
}
// test invalid operation
_, rosettaError = GetOperationComponents([]*types.Operation{
{
Type: common.ExpendGasOperation,
},
})
if rosettaError == nil {
t.Error("expected error")
}
// test nil operation
_, rosettaError = GetOperationComponents(nil)
if rosettaError == nil {
t.Error("expected error")
}
}