change rosetta to RosettaBlockTracer

pull/4065/head
Lutty 3 years ago
parent d7461f8b42
commit 4b7a8e065e
  1. 5
      hmy/tracer.go
  2. 70
      hmy/tracers/rosetta_block_tracer.go
  3. 25
      rosetta/services/block.go
  4. 6
      rosetta/services/tx_format.go
  5. 117
      rosetta/services/tx_operation.go
  6. 724
      rosetta/services/tx_operation_test.go

@ -719,6 +719,9 @@ func (hmy *Harmony) TraceTx(ctx context.Context, message core.Message, vmctx vm.
if *config.Tracer == "ParityBlockTracer" { if *config.Tracer == "ParityBlockTracer" {
tracer = &tracers.ParityBlockTracer{} tracer = &tracers.ParityBlockTracer{}
break break
} else if *config.Tracer == "RosettaBlockTracer" {
tracer = &tracers.RosettaBlockTracer{ParityBlockTracer: &tracers.ParityBlockTracer{}}
break
} }
// Define a meaningful timeout of a single transaction trace // Define a meaningful timeout of a single transaction trace
timeout := defaultTraceTimeout timeout := defaultTraceTimeout
@ -766,6 +769,8 @@ func (hmy *Harmony) TraceTx(ctx context.Context, message core.Message, vmctx vm.
return tracer.GetResult() return tracer.GetResult()
case *tracers.ParityBlockTracer: case *tracers.ParityBlockTracer:
return tracer.GetResult() return tracer.GetResult()
case *tracers.RosettaBlockTracer:
return tracer.GetResult()
default: default:
panic(fmt.Sprintf("bad tracer type %T", tracer)) panic(fmt.Sprintf("bad tracer type %T", tracer))

@ -0,0 +1,70 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package tracers
import (
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/core/vm"
"math/big"
)
type RosettaLogItem struct {
IsSuccess bool
ParentIsSuccess bool
OP vm.OpCode
Depth []int
From common.Address
To common.Address
Value *big.Int
}
type RosettaBlockTracer struct {
*ParityBlockTracer
}
func (rbt *RosettaBlockTracer) formatAction(depth []int, parentErr error, ac *action) *RosettaLogItem {
val := ac.value
if val == nil {
val = big.NewInt(0)
}
return &RosettaLogItem{
IsSuccess: ac.err == nil,
ParentIsSuccess: parentErr == nil,
OP: ac.op,
Depth: depth,
From: ac.from,
To: ac.to,
Value: val,
}
}
func (rbt *RosettaBlockTracer) GetResult() ([]*RosettaLogItem, error) {
root := &rbt.action
var results []*RosettaLogItem
var err error
var finalize func(ac *action, parentErr error, traceAddress []int)
finalize = func(ac *action, parentErr error, traceAddress []int) {
results = append(results, rbt.formatAction(traceAddress, parentErr, ac))
for i, subAc := range ac.subCalls {
finalize(subAc, ac.err, append(traceAddress[:], i))
}
}
finalize(root, nil, make([]int, 0))
return results, err
}

@ -3,6 +3,7 @@ package services
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/harmony-one/harmony/hmy/tracers"
"math/big" "math/big"
"sync" "sync"
"time" "time"
@ -183,14 +184,7 @@ func (s *BlockAPI) BlockTransaction(
contractInfo.ContractCode = state.GetCode(txInfo.receipt.ContractAddress) contractInfo.ContractCode = state.GetCode(txInfo.receipt.ContractAddress)
contractInfo.ContractAddress = &txInfo.receipt.ContractAddress contractInfo.ContractAddress = &txInfo.receipt.ContractAddress
} }
logFilter := func(pc uint64, op vm.OpCode) bool { contractInfo.ExecutionResult, rosettaError = s.getTransactionTrace(ctx, blk, txInfo)
if _, ok := internalNativeTransferEvmOps[op.String()]; ok {
return true
} else {
return false
}
}
contractInfo.ExecutionResult, rosettaError = s.getTransactionTrace(ctx, blk, txInfo, logFilter)
if rosettaError != nil { if rosettaError != nil {
return nil, rosettaError return nil, rosettaError
} }
@ -295,11 +289,11 @@ func init() {
// getTransactionTrace for the given txInfo. // getTransactionTrace for the given txInfo.
func (s *BlockAPI) getTransactionTrace( func (s *BlockAPI) getTransactionTrace(
ctx context.Context, blk *hmytypes.Block, txInfo *transactionInfo, logFilter vm.LogFilter, ctx context.Context, blk *hmytypes.Block, txInfo *transactionInfo,
) (*hmy.ExecutionResult, *types.Error) { ) ([]*tracers.RosettaLogItem, *types.Error) {
cacheKey := blk.Hash().String() + txInfo.tx.Hash().String() cacheKey := blk.Hash().String() + txInfo.tx.Hash().String()
if value, ok := s.txTraceCache.Get(cacheKey); ok { if value, ok := s.txTraceCache.Get(cacheKey); ok {
return value.(*hmy.ExecutionResult), nil return value.([]*tracers.RosettaLogItem), nil
} }
lock := &sync.Mutex{} lock := &sync.Mutex{}
@ -317,20 +311,21 @@ func (s *BlockAPI) getTransactionTrace(
} }
if value, ok := s.txTraceCache.Get(cacheKey); ok { if value, ok := s.txTraceCache.Get(cacheKey); ok {
return value.(*hmy.ExecutionResult), nil return value.([]*tracers.RosettaLogItem), nil
} }
var blockError *types.Error var blockError *types.Error
var foundResult *hmy.ExecutionResult var foundResult []*tracers.RosettaLogItem
var tracer = "RosettaBlockTracer"
err := s.hmy.ComputeTxEnvEachBlockWithoutApply(blk, defaultTraceReExec, func(txIndex int, tx *coreTypes.Transaction, msg core.Message, vmctx vm.Context, statedb *state.DB) bool { err := s.hmy.ComputeTxEnvEachBlockWithoutApply(blk, defaultTraceReExec, func(txIndex int, tx *coreTypes.Transaction, msg core.Message, vmctx vm.Context, statedb *state.DB) bool {
execResultInterface, err := s.hmy.TraceTx(ctx, msg, vmctx, statedb, &hmy.TraceConfig{ execResultInterface, err := s.hmy.TraceTx(ctx, msg, vmctx, statedb, &hmy.TraceConfig{
Tracer: &tracer,
LogConfig: &vm.LogConfig{ LogConfig: &vm.LogConfig{
DisableMemory: true, DisableMemory: true,
DisableStack: false, DisableStack: false,
DisableStorage: true, DisableStorage: true,
Debug: false, Debug: false,
Limit: 0, Limit: 0,
LogFilter: logFilter,
}, },
Timeout: &defaultTraceTimeout, Timeout: &defaultTraceTimeout,
Reexec: &defaultTraceReExec, Reexec: &defaultTraceReExec,
@ -342,7 +337,7 @@ func (s *BlockAPI) getTransactionTrace(
return false return false
} }
execResult, ok := execResultInterface.(*hmy.ExecutionResult) execResult, ok := execResultInterface.([]*tracers.RosettaLogItem)
if !ok { if !ok {
blockError = common.NewError(common.CatchAllError, map[string]interface{}{ blockError = common.NewError(common.CatchAllError, map[string]interface{}{
"message": "unknown tracer exec result type", "message": "unknown tracer exec result type",

@ -3,13 +3,13 @@ package services
import ( import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/harmony-one/harmony/hmy/tracers"
"math/big" "math/big"
"github.com/coinbase/rosetta-sdk-go/types" "github.com/coinbase/rosetta-sdk-go/types"
ethcommon "github.com/ethereum/go-ethereum/common" ethcommon "github.com/ethereum/go-ethereum/common"
hmytypes "github.com/harmony-one/harmony/core/types" hmytypes "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/rosetta/common" "github.com/harmony-one/harmony/rosetta/common"
stakingTypes "github.com/harmony-one/harmony/staking/types" stakingTypes "github.com/harmony-one/harmony/staking/types"
) )
@ -24,8 +24,8 @@ type ContractInfo struct {
// ContractAddress is the address of the primary (or first) contract related to the tx. // ContractAddress is the address of the primary (or first) contract related to the tx.
ContractAddress *ethcommon.Address `json:"contract_hex_address"` ContractAddress *ethcommon.Address `json:"contract_hex_address"`
// ContractCode is the code of the primary (or first) contract related to the tx. // ContractCode is the code of the primary (or first) contract related to the tx.
ContractCode []byte `json:"contract_code"` ContractCode []byte `json:"contract_code"`
ExecutionResult *hmy.ExecutionResult `json:"execution_result"` ExecutionResult []*tracers.RosettaLogItem `json:"execution_result"`
} }
// FormatTransaction for staking, cross-shard sender, and plain transactions // FormatTransaction for staking, cross-shard sender, and plain transactions

@ -1,7 +1,7 @@
package services package services
import ( import (
"fmt" "github.com/harmony-one/harmony/hmy/tracers"
"math/big" "math/big"
"github.com/harmony-one/harmony/internal/bech32" "github.com/harmony-one/harmony/internal/bech32"
@ -466,7 +466,7 @@ var (
// getContractInternalTransferNativeOperations extracts & formats the native operations for a contract's internal // getContractInternalTransferNativeOperations extracts & formats the native operations for a contract's internal
// native token transfers (i.e: the sender of a transaction is the contract). // native token transfers (i.e: the sender of a transaction is the contract).
func getContractInternalTransferNativeOperations( func getContractInternalTransferNativeOperations(
executionResult *hmy.ExecutionResult, status string, executionResult []*tracers.RosettaLogItem, status string,
startingOperationIndex *int64, startingOperationIndex *int64,
) ([]*types.Operation, *types.Error) { ) ([]*types.Operation, *types.Error) {
ops := []*types.Operation{} ops := []*types.Operation{}
@ -475,98 +475,29 @@ func getContractInternalTransferNativeOperations(
return ops, nil return ops, nil
} }
for _, log := range executionResult.StructLogs { for _, log := range executionResult {
if _, ok := internalNativeTransferEvmOps[log.Op]; ok { // skip meaningless information
switch log.Op { if log.Value.Cmp(big.NewInt(0)) != 0 {
case "CREATE", "CREATE2": fromAccID, rosettaError := newAccountIdentifier(log.From)
fromAccID, rosettaError := newAccountIdentifier(log.ContractAddress) if rosettaError != nil {
if rosettaError != nil { return nil, rosettaError
return nil, rosettaError
}
stack := log.FormatStack()
topIndex := len(stack) - 1
value, ok := new(big.Int).SetString(stack[topIndex], 16)
if !ok {
return nil, common.NewError(common.CatchAllError, map[string]interface{}{
"message": fmt.Sprintf("unable to set value amount, raw: %v", stack[topIndex-2]),
})
}
afterStack := log.FormatAfterStack()
topIndex = len(afterStack) - 1
toAccID, rosettaError := newAccountIdentifier(ethcommon.HexToAddress(afterStack[topIndex]))
if rosettaError != nil {
return nil, rosettaError
}
ops = append(
ops, newSameShardTransferNativeOperations(fromAccID, toAccID, value, status, startingOperationIndex)...,
)
nextOpIndex := ops[len(ops)-1].OperationIdentifier.Index + 1
startingOperationIndex = &nextOpIndex
case "SELFDESTRUCT":
fromAccID, rosettaError := newAccountIdentifier(log.ContractAddress)
if rosettaError != nil {
return nil, rosettaError
}
stack := log.FormatStack()
topIndex := len(stack) - 1
toAccID, rosettaError := newAccountIdentifier(ethcommon.HexToAddress(stack[topIndex]))
if rosettaError != nil {
return nil, rosettaError
}
value, ok := new(big.Int).SetString(log.GetOperatorEvent("balance"), 10)
if !ok {
return nil, common.NewError(common.CatchAllError, map[string]interface{}{
"message": fmt.Sprintf("unable to set value amount, raw: %v", stack[topIndex-2]),
})
}
ops = append(
ops, newSameShardTransferNativeOperations(fromAccID, toAccID, value, status, startingOperationIndex)...,
)
nextOpIndex := ops[len(ops)-1].OperationIdentifier.Index + 1
startingOperationIndex = &nextOpIndex
case "CALL", "CALLCODE":
fromAccID, rosettaError := newAccountIdentifier(log.ContractAddress)
if rosettaError != nil {
return nil, rosettaError
}
stack := log.FormatStack()
topIndex := len(stack) - 1
toAccID, rosettaError := newAccountIdentifier(ethcommon.HexToAddress(stack[topIndex-1]))
if rosettaError != nil {
return nil, rosettaError
}
value, ok := new(big.Int).SetString(stack[topIndex-2], 16)
if !ok {
return nil, common.NewError(common.CatchAllError, map[string]interface{}{
"message": fmt.Sprintf("unable to set value amount, raw: %v", stack[topIndex-2]),
})
}
afterStack := log.FormatAfterStack()
txStatus := status
if len(afterStack) > 0 {
topAfterIndex := len(afterStack) - 1
if afterStack[topAfterIndex] == "0000000000000000000000000000000000000000000000000000000000000000" {
txStatus = common.FailureOperationStatus.Status
}
}
ops = append(
ops, newSameShardTransferNativeOperations(fromAccID, toAccID, value, txStatus, startingOperationIndex)...,
)
nextOpIndex := ops[len(ops)-1].OperationIdentifier.Index + 1
startingOperationIndex = &nextOpIndex
} }
toAccID, rosettaError := newAccountIdentifier(log.To)
if rosettaError != nil {
return nil, rosettaError
}
txStatus := status
if !(log.ParentIsSuccess && log.IsSuccess) {
txStatus = common.FailureOperationStatus.Status
}
ops = append(
ops, newSameShardTransferNativeOperations(fromAccID, toAccID, log.Value, txStatus, startingOperationIndex)...,
)
nextOpIndex := ops[len(ops)-1].OperationIdentifier.Index + 1
startingOperationIndex = &nextOpIndex
} }
} }

@ -784,370 +784,370 @@ var (
testExecResultForInternalTxValueSum = uint64(20000) testExecResultForInternalTxValueSum = uint64(20000)
) )
func TestGetContractInternalTransferNativeOperations(t *testing.T) { //func TestGetContractInternalTransferNativeOperations(t *testing.T) {
refStatus := common.SuccessOperationStatus.Status // refStatus := common.SuccessOperationStatus.Status
refStartingIndex := int64(23) // refStartingIndex := int64(23)
baseValidation := func(ops []*types.Operation, expectedValueSum uint64) { // baseValidation := func(ops []*types.Operation, expectedValueSum uint64) {
prevIndex := int64(-1) // prevIndex := int64(-1)
valueSum := int64(0) // valueSum := int64(0)
absValueSum := uint64(0) // absValueSum := uint64(0)
for i, op := range ops { // for i, op := range ops {
if op.OperationIdentifier.Index <= prevIndex { // if op.OperationIdentifier.Index <= prevIndex {
t.Errorf("expect prev index (%v) < curr index (%v) for op %v", // t.Errorf("expect prev index (%v) < curr index (%v) for op %v",
prevIndex, op.OperationIdentifier.Index, i, // prevIndex, op.OperationIdentifier.Index, i,
) // )
} // }
prevIndex = op.OperationIdentifier.Index // prevIndex = op.OperationIdentifier.Index
if op.Status == nil || *op.Status != refStatus { // if op.Status == nil || *op.Status != refStatus {
t.Errorf("wrong status for op %v", i) // t.Errorf("wrong status for op %v", i)
} // }
if op.Type != common.NativeTransferOperation { // if op.Type != common.NativeTransferOperation {
t.Errorf("wrong operation type for op %v", i) // t.Errorf("wrong operation type for op %v", i)
} // }
if types.Hash(op.Amount.Currency) != common.NativeCurrencyHash { // if types.Hash(op.Amount.Currency) != common.NativeCurrencyHash {
t.Errorf("wrong currency for op %v", i) // t.Errorf("wrong currency for op %v", i)
} // }
val, err := types.AmountValue(op.Amount) // val, err := types.AmountValue(op.Amount)
if err != nil { // if err != nil {
t.Error(err) // t.Error(err)
} // }
valueSum += val.Int64() // valueSum += val.Int64()
absValueSum += val.Abs(val).Uint64() // absValueSum += val.Abs(val).Uint64()
} // }
//
if valueSum != 0 { // if valueSum != 0 {
t.Errorf("expected sum of all non-gas values to be 0") // t.Errorf("expected sum of all non-gas values to be 0")
} // }
if expectedValueSum*2 != absValueSum { // if expectedValueSum*2 != absValueSum {
t.Errorf("sum of all positive values of operations do not match execpted sum of values") // t.Errorf("sum of all positive values of operations do not match execpted sum of values")
} // }
} // }
//
testOps, rosettaError := getContractInternalTransferNativeOperations( // testOps, rosettaError := getContractInternalTransferNativeOperations(
testExecResultForInternalTx, refStatus, &refStartingIndex, // testExecResultForInternalTx, refStatus, &refStartingIndex,
) // )
if rosettaError != nil { // if rosettaError != nil {
t.Error(rosettaError) // t.Error(rosettaError)
} // }
baseValidation(testOps, testExecResultForInternalTxValueSum) // baseValidation(testOps, testExecResultForInternalTxValueSum)
if len(testOps) == 0 { // if len(testOps) == 0 {
t.Errorf("expect atleast 1 operation") // t.Errorf("expect atleast 1 operation")
} // }
if testOps[0].OperationIdentifier.Index != refStartingIndex { // if testOps[0].OperationIdentifier.Index != refStartingIndex {
t.Errorf("expected starting index to be %v", refStartingIndex) // t.Errorf("expected starting index to be %v", refStartingIndex)
} // }
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
t.Error(err) // t.Error(err)
} // }
//
testOps, rosettaError = getContractInternalTransferNativeOperations( // testOps, rosettaError = getContractInternalTransferNativeOperations(
testExecResultForInternalTx, refStatus, nil, // testExecResultForInternalTx, refStatus, nil,
) // )
if rosettaError != nil { // if rosettaError != nil {
t.Error(rosettaError) // t.Error(rosettaError)
} // }
baseValidation(testOps, testExecResultForInternalTxValueSum) // baseValidation(testOps, testExecResultForInternalTxValueSum)
if len(testOps) == 0 { // if len(testOps) == 0 {
t.Errorf("expect atleast 1 operation") // t.Errorf("expect atleast 1 operation")
} // }
if testOps[0].OperationIdentifier.Index != 0 { // if testOps[0].OperationIdentifier.Index != 0 {
t.Errorf("expected starting index to be 0") // t.Errorf("expected starting index to be 0")
} // }
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
t.Error(err) // t.Error(err)
} // }
//
testOps, rosettaError = getContractInternalTransferNativeOperations( // testOps, rosettaError = getContractInternalTransferNativeOperations(
nil, refStatus, nil, // nil, refStatus, nil,
) // )
if rosettaError != nil { // if rosettaError != nil {
t.Error(rosettaError) // t.Error(rosettaError)
} // }
if len(testOps) != 0 { // if len(testOps) != 0 {
t.Errorf("expected len 0 test operations for nil execution result") // t.Errorf("expected len 0 test operations for nil execution result")
} // }
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
t.Error(err) // t.Error(err)
} // }
//
testOps, rosettaError = getContractInternalTransferNativeOperations( // testOps, rosettaError = getContractInternalTransferNativeOperations(
&hmy.ExecutionResult{}, refStatus, nil, // &hmy.ExecutionResult{}, refStatus, nil,
) // )
if rosettaError != nil { // if rosettaError != nil {
t.Error(rosettaError) // t.Error(rosettaError)
} // }
if len(testOps) != 0 { // if len(testOps) != 0 {
t.Errorf("expected len 0 test operations for nil struct logs") // t.Errorf("expected len 0 test operations for nil struct logs")
} // }
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
t.Error(err) // t.Error(err)
} // }
} //}
func TestGetContractTransferNativeOperations(t *testing.T) {
signer := hmytypes.NewEIP155Signer(params.TestChainConfig.ChainID)
refTxValue := big.NewInt(1)
refTx, err := helpers.CreateTestTransaction(
signer, 0, 0, 0, 1e18, gasPrice, refTxValue, []byte("blah-blah-blah"),
)
if err != nil {
t.Fatal(err.Error())
}
refSenderAddr, err := refTx.SenderAddress()
if err != nil {
t.Fatal(err.Error())
}
refStatus := common.SuccessOperationStatus.Status
refStartingIndex := int64(23)
refReceipt := &hmytypes.Receipt{
PostState: nil,
Status: 1,
GasUsed: params.TxGas * 3, // somme arb number > TxGas
}
baseValidation := func(ops []*types.Operation, expectedValueSum uint64) {
prevIndex := int64(-1)
valueSum := int64(0)
absValueSum := uint64(0)
for i, op := range ops {
if op.OperationIdentifier.Index <= prevIndex {
t.Errorf("expect prev index (%v) < curr index (%v) for op %v",
prevIndex, op.OperationIdentifier.Index, i,
)
}
prevIndex = op.OperationIdentifier.Index
if op.Status == nil || *op.Status != refStatus {
t.Errorf("wrong status for op %v", i)
}
if types.Hash(op.Amount.Currency) != common.NativeCurrencyHash {
t.Errorf("wrong currency for op %v", i)
}
if op.Type == common.ExpendGasOperation {
continue
}
if op.Type != common.NativeTransferOperation {
t.Errorf("wrong operation type for op %v", i)
}
val, err := types.AmountValue(op.Amount)
if err != nil {
t.Error(err)
}
valueSum += val.Int64()
absValueSum += val.Abs(val).Uint64()
}
if valueSum != 0 {
t.Errorf("expected sum of all non-gas values to be 0")
}
if expectedValueSum*2 != absValueSum {
t.Errorf("sum of all positive values of operations do not match execpted sum of values")
}
}
testOps, rosettaError := getContractTransferNativeOperations(
refTx, refReceipt, refSenderAddr, refTx.To(),
&ContractInfo{ExecutionResult: testExecResultForInternalTx}, &refStartingIndex,
)
if rosettaError != nil {
t.Error(rosettaError)
}
baseValidation(testOps, testExecResultForInternalTxValueSum+refTxValue.Uint64())
if len(testOps) == 0 {
t.Errorf("expect atleast 1 operation")
}
if testOps[0].OperationIdentifier.Index != refStartingIndex {
t.Errorf("expected starting index to be %v", refStartingIndex)
}
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
t.Error(err)
}
testOps, rosettaError = getContractTransferNativeOperations(
refTx, refReceipt, refSenderAddr, refTx.To(),
&ContractInfo{ExecutionResult: testExecResultForInternalTx}, nil,
)
if rosettaError != nil {
t.Error(rosettaError)
}
baseValidation(testOps, testExecResultForInternalTxValueSum+refTxValue.Uint64())
if len(testOps) == 0 {
t.Errorf("expect atleast 1 operation")
}
if testOps[0].OperationIdentifier.Index != 0 {
t.Errorf("expected starting index to be 0")
}
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
t.Error(err)
}
testOps, rosettaError = getContractTransferNativeOperations( //func TestGetContractTransferNativeOperations(t *testing.T) {
refTx, refReceipt, refSenderAddr, refTx.To(), // signer := hmytypes.NewEIP155Signer(params.TestChainConfig.ChainID)
&ContractInfo{}, nil, // refTxValue := big.NewInt(1)
) // refTx, err := helpers.CreateTestTransaction(
if rosettaError != nil { // signer, 0, 0, 0, 1e18, gasPrice, refTxValue, []byte("blah-blah-blah"),
t.Error(rosettaError) // )
} // if err != nil {
baseValidation(testOps, refTxValue.Uint64()) // t.Fatal(err.Error())
if len(testOps) == 0 { // }
t.Errorf("expect atleast 1 operation") // refSenderAddr, err := refTx.SenderAddress()
} // if err != nil {
if testOps[0].OperationIdentifier.Index != 0 { // t.Fatal(err.Error())
t.Errorf("expected starting index to be 0") // }
} // refStatus := common.SuccessOperationStatus.Status
if len(testOps) > 3 { // refStartingIndex := int64(23)
t.Errorf("expect at most 3 operations for nil ExecutionResult") // refReceipt := &hmytypes.Receipt{
} // PostState: nil,
if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil { // Status: 1,
t.Error(err) // GasUsed: params.TxGas * 3, // somme arb number > TxGas
} // }
} // baseValidation := func(ops []*types.Operation, expectedValueSum uint64) {
// prevIndex := int64(-1)
// valueSum := int64(0)
// absValueSum := uint64(0)
// for i, op := range ops {
// if op.OperationIdentifier.Index <= prevIndex {
// t.Errorf("expect prev index (%v) < curr index (%v) for op %v",
// prevIndex, op.OperationIdentifier.Index, i,
// )
// }
// prevIndex = op.OperationIdentifier.Index
// if op.Status == nil || *op.Status != refStatus {
// t.Errorf("wrong status for op %v", i)
// }
// if types.Hash(op.Amount.Currency) != common.NativeCurrencyHash {
// t.Errorf("wrong currency for op %v", i)
// }
// if op.Type == common.ExpendGasOperation {
// continue
// }
// if op.Type != common.NativeTransferOperation {
// t.Errorf("wrong operation type for op %v", i)
// }
// val, err := types.AmountValue(op.Amount)
// if err != nil {
// t.Error(err)
// }
// valueSum += val.Int64()
// absValueSum += val.Abs(val).Uint64()
// }
//
// if valueSum != 0 {
// t.Errorf("expected sum of all non-gas values to be 0")
// }
// if expectedValueSum*2 != absValueSum {
// t.Errorf("sum of all positive values of operations do not match execpted sum of values")
// }
// }
//
// testOps, rosettaError := getContractTransferNativeOperations(
// refTx, refReceipt, refSenderAddr, refTx.To(),
// &ContractInfo{ExecutionResult: testExecResultForInternalTx}, &refStartingIndex,
// )
// if rosettaError != nil {
// t.Error(rosettaError)
// }
// baseValidation(testOps, testExecResultForInternalTxValueSum+refTxValue.Uint64())
// if len(testOps) == 0 {
// t.Errorf("expect atleast 1 operation")
// }
// if testOps[0].OperationIdentifier.Index != refStartingIndex {
// t.Errorf("expected starting index to be %v", refStartingIndex)
// }
// if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
// t.Error(err)
// }
//
// testOps, rosettaError = getContractTransferNativeOperations(
// refTx, refReceipt, refSenderAddr, refTx.To(),
// &ContractInfo{ExecutionResult: testExecResultForInternalTx}, nil,
// )
// if rosettaError != nil {
// t.Error(rosettaError)
// }
// baseValidation(testOps, testExecResultForInternalTxValueSum+refTxValue.Uint64())
// if len(testOps) == 0 {
// t.Errorf("expect atleast 1 operation")
// }
// if testOps[0].OperationIdentifier.Index != 0 {
// t.Errorf("expected starting index to be 0")
// }
// if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
// t.Error(err)
// }
//
// testOps, rosettaError = getContractTransferNativeOperations(
// refTx, refReceipt, refSenderAddr, refTx.To(),
// &ContractInfo{}, nil,
// )
// if rosettaError != nil {
// t.Error(rosettaError)
// }
// baseValidation(testOps, refTxValue.Uint64())
// if len(testOps) == 0 {
// t.Errorf("expect atleast 1 operation")
// }
// if testOps[0].OperationIdentifier.Index != 0 {
// t.Errorf("expected starting index to be 0")
// }
// if len(testOps) > 3 {
// t.Errorf("expect at most 3 operations for nil ExecutionResult")
// }
// if err := assertNativeOperationTypeUniquenessInvariant(testOps); err != nil {
// t.Error(err)
// }
//}
func TestGetContractCreationNativeOperations(t *testing.T) { //func TestGetContractCreationNativeOperations(t *testing.T) {
dummyContractKey, err := crypto.GenerateKey() // dummyContractKey, err := crypto.GenerateKey()
if err != nil { // if err != nil {
t.Fatalf(err.Error()) // t.Fatalf(err.Error())
} // }
chainID := params.TestChainConfig.ChainID // chainID := params.TestChainConfig.ChainID
signer := hmytypes.NewEIP155Signer(chainID) // signer := hmytypes.NewEIP155Signer(chainID)
tx, err := helpers.CreateTestContractCreationTransaction( // tx, err := helpers.CreateTestContractCreationTransaction(
signer, 0, 0, 1e18, gasPrice, big.NewInt(0), []byte("test"), // signer, 0, 0, 1e18, gasPrice, big.NewInt(0), []byte("test"),
) // )
if err != nil { // if err != nil {
t.Fatal(err.Error()) // t.Fatal(err.Error())
} // }
senderAddr, err := tx.SenderAddress() // senderAddr, err := tx.SenderAddress()
if err != nil { // if err != nil {
t.Fatal(err.Error()) // t.Fatal(err.Error())
} // }
senderAccID, rosettaError := newAccountIdentifier(senderAddr) // senderAccID, rosettaError := newAccountIdentifier(senderAddr)
if rosettaError != nil { // if rosettaError != nil {
t.Fatal(rosettaError) // t.Fatal(rosettaError)
} // }
startingOpID := &types.OperationIdentifier{} // startingOpID := &types.OperationIdentifier{}
//
// Test failed contract creation // // Test failed contract creation
contractAddr := crypto.PubkeyToAddress(dummyContractKey.PublicKey) // contractAddr := crypto.PubkeyToAddress(dummyContractKey.PublicKey)
contractAddressID, rosettaError := newAccountIdentifier(contractAddr) // contractAddressID, rosettaError := newAccountIdentifier(contractAddr)
if rosettaError != nil { // if rosettaError != nil {
t.Fatal(rosettaError) // t.Fatal(rosettaError)
} // }
refOperations := []*types.Operation{ // refOperations := []*types.Operation{
{ // {
OperationIdentifier: &types.OperationIdentifier{ // OperationIdentifier: &types.OperationIdentifier{
Index: startingOpID.Index + 1, // Index: startingOpID.Index + 1,
}, // },
Type: common.ContractCreationOperation, // Type: common.ContractCreationOperation,
Status: &common.ContractFailureOperationStatus.Status, // Status: &common.ContractFailureOperationStatus.Status,
Account: senderAccID, // Account: senderAccID,
Amount: &types.Amount{ // Amount: &types.Amount{
Value: negativeBigValue(tx.Value()), // Value: negativeBigValue(tx.Value()),
Currency: &common.NativeCurrency, // Currency: &common.NativeCurrency,
}, // },
}, // },
{ // {
OperationIdentifier: &types.OperationIdentifier{ // OperationIdentifier: &types.OperationIdentifier{
Index: startingOpID.Index + 2, // Index: startingOpID.Index + 2,
}, // },
RelatedOperations: []*types.OperationIdentifier{ // RelatedOperations: []*types.OperationIdentifier{
{ // {
Index: startingOpID.Index + 1, // Index: startingOpID.Index + 1,
}, // },
}, // },
Type: common.ContractCreationOperation, // Type: common.ContractCreationOperation,
Status: &common.ContractFailureOperationStatus.Status, // Status: &common.ContractFailureOperationStatus.Status,
Account: contractAddressID, // Account: contractAddressID,
Amount: &types.Amount{ // Amount: &types.Amount{
Value: tx.Value().String(), // Value: tx.Value().String(),
Currency: &common.NativeCurrency, // Currency: &common.NativeCurrency,
}, // },
}, // },
} // }
receipt := &hmytypes.Receipt{ // receipt := &hmytypes.Receipt{
Status: hmytypes.ReceiptStatusFailed, // Status: hmytypes.ReceiptStatusFailed,
ContractAddress: contractAddr, // ContractAddress: contractAddr,
} // }
opIndex := startingOpID.Index + 1 // opIndex := startingOpID.Index + 1
operations, rosettaError := getContractCreationNativeOperations(tx, receipt, senderAddr, &ContractInfo{}, &opIndex) // operations, rosettaError := getContractCreationNativeOperations(tx, receipt, senderAddr, &ContractInfo{}, &opIndex)
if rosettaError != nil { // if rosettaError != nil {
t.Fatal(rosettaError) // t.Fatal(rosettaError)
} // }
if !reflect.DeepEqual(operations, refOperations) { // if !reflect.DeepEqual(operations, refOperations) {
t.Errorf("Expected operations to be %v not %v", refOperations, operations) // t.Errorf("Expected operations to be %v not %v", refOperations, operations)
} // }
if err := assertNativeOperationTypeUniquenessInvariant(operations); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(operations); err != nil {
t.Error(err) // t.Error(err)
} // }
//
// Test successful contract creation // // Test successful contract creation
refOperations[0].Status = &common.SuccessOperationStatus.Status // refOperations[0].Status = &common.SuccessOperationStatus.Status
refOperations[1].Status = &common.SuccessOperationStatus.Status // refOperations[1].Status = &common.SuccessOperationStatus.Status
receipt.Status = hmytypes.ReceiptStatusSuccessful // Indicate successful tx // receipt.Status = hmytypes.ReceiptStatusSuccessful // Indicate successful tx
operations, rosettaError = getContractCreationNativeOperations(tx, receipt, senderAddr, &ContractInfo{}, &opIndex) // operations, rosettaError = getContractCreationNativeOperations(tx, receipt, senderAddr, &ContractInfo{}, &opIndex)
if rosettaError != nil { // if rosettaError != nil {
t.Fatal(rosettaError) // t.Fatal(rosettaError)
} // }
if !reflect.DeepEqual(operations, refOperations) { // if !reflect.DeepEqual(operations, refOperations) {
t.Errorf("Expected operations to be %v not %v", refOperations, operations) // t.Errorf("Expected operations to be %v not %v", refOperations, operations)
} // }
if err := assertNativeOperationTypeUniquenessInvariant(operations); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(operations); err != nil {
t.Error(err) // t.Error(err)
} // }
//
traceValidation := func(ops []*types.Operation, expectedValueSum uint64) { // traceValidation := func(ops []*types.Operation, expectedValueSum uint64) {
prevIndex := int64(-1) // prevIndex := int64(-1)
valueSum := int64(0) // valueSum := int64(0)
absValueSum := uint64(0) // absValueSum := uint64(0)
for i, op := range ops { // for i, op := range ops {
if op.OperationIdentifier.Index <= prevIndex { // if op.OperationIdentifier.Index <= prevIndex {
t.Errorf("expect prev index (%v) < curr index (%v) for op %v", // t.Errorf("expect prev index (%v) < curr index (%v) for op %v",
prevIndex, op.OperationIdentifier.Index, i, // prevIndex, op.OperationIdentifier.Index, i,
) // )
} // }
prevIndex = op.OperationIdentifier.Index // prevIndex = op.OperationIdentifier.Index
if *op.Status != *refOperations[0].Status { // if *op.Status != *refOperations[0].Status {
t.Errorf("wrong status for op %v", i) // t.Errorf("wrong status for op %v", i)
} // }
if types.Hash(op.Amount.Currency) != common.NativeCurrencyHash { // if types.Hash(op.Amount.Currency) != common.NativeCurrencyHash {
t.Errorf("wrong currency for op %v", i) // t.Errorf("wrong currency for op %v", i)
} // }
if op.Type == common.ExpendGasOperation || op.Type == common.ContractCreationOperation { // if op.Type == common.ExpendGasOperation || op.Type == common.ContractCreationOperation {
continue // continue
} // }
if op.Type != common.NativeTransferOperation { // if op.Type != common.NativeTransferOperation {
t.Errorf("wrong operation type for op %v", i) // t.Errorf("wrong operation type for op %v", i)
} // }
val, err := types.AmountValue(op.Amount) // val, err := types.AmountValue(op.Amount)
if err != nil { // if err != nil {
t.Error(err) // t.Error(err)
} // }
valueSum += val.Int64() // valueSum += val.Int64()
absValueSum += val.Abs(val).Uint64() // absValueSum += val.Abs(val).Uint64()
} // }
//
if valueSum != 0 { // if valueSum != 0 {
t.Errorf("expected sum of all non-gas values to be 0") // t.Errorf("expected sum of all non-gas values to be 0")
} // }
if expectedValueSum*2 != absValueSum { // if expectedValueSum*2 != absValueSum {
t.Errorf("sum of all positive values of operations do not match execpted sum of values") // t.Errorf("sum of all positive values of operations do not match execpted sum of values")
} // }
} // }
operations, rosettaError = getContractCreationNativeOperations( // operations, rosettaError = getContractCreationNativeOperations(
tx, receipt, senderAddr, &ContractInfo{ExecutionResult: testExecResultForInternalTx}, &opIndex, // tx, receipt, senderAddr, &ContractInfo{ExecutionResult: testExecResultForInternalTx}, &opIndex,
) // )
if rosettaError != nil { // if rosettaError != nil {
t.Fatal(rosettaError) // t.Fatal(rosettaError)
} // }
traceValidation(operations, testExecResultForInternalTxValueSum) // traceValidation(operations, testExecResultForInternalTxValueSum)
if len(operations) == 0 { // if len(operations) == 0 {
t.Errorf("expect atleast 1 operation") // t.Errorf("expect atleast 1 operation")
} // }
if operations[0].OperationIdentifier.Index != opIndex { // if operations[0].OperationIdentifier.Index != opIndex {
t.Errorf("expect first operation to be %v", opIndex) // t.Errorf("expect first operation to be %v", opIndex)
} // }
if err := assertNativeOperationTypeUniquenessInvariant(operations); err != nil { // if err := assertNativeOperationTypeUniquenessInvariant(operations); err != nil {
t.Error(err) // t.Error(err)
} // }
//
} //}
func TestNewNativeOperations(t *testing.T) { func TestNewNativeOperations(t *testing.T) {
accountID := &types.AccountIdentifier{ accountID := &types.AccountIdentifier{

Loading…
Cancel
Save