Skip to content

Commit 471388b

Browse files
authored
Merge branch 'master' into paul/tobin-tax-removal
2 parents 2cedb9d + 43eecf0 commit 471388b

File tree

8 files changed

+371
-21
lines changed

8 files changed

+371
-21
lines changed

core/vm/contracts.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ func (c *transfer) Run(input []byte, caller common.Address, evm *EVM) ([]byte, e
698698
// to: 32 bytes representing the address of the recipient
699699
// value: 32 bytes, a 256 bit integer representing the amount of Celo Gold to transfer
700700
// 3 arguments x 32 bytes each = 96 bytes total input
701-
if (evm.chainRules.IsGFork && len(input) != 96) || len(input) <= 96 {
701+
if (evm.chainRules.IsGFork && len(input) != 96) || len(input) < 96 {
702702
return nil, ErrInputLength
703703
}
704704

e2e_test/e2e_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/celo-org/celo-blockchain/common"
1515
"github.com/celo-org/celo-blockchain/common/hexutil"
1616
"github.com/celo-org/celo-blockchain/core/types"
17+
"github.com/celo-org/celo-blockchain/eth/tracers"
1718
"github.com/celo-org/celo-blockchain/log"
1819
"github.com/celo-org/celo-blockchain/node"
1920
"github.com/celo-org/celo-blockchain/rpc"
@@ -55,6 +56,41 @@ func TestSendCelo(t *testing.T) {
5556
require.NoError(t, err)
5657
}
5758

59+
// This test starts a network, submits a GoldToken.transfer tx, waits for the whole
60+
// network to process the transaction, and traces that tx.
61+
// This tests that CELO transfers made via the transfer precompile work e2e
62+
// and can be useful for debugging these traces.
63+
func TestTraceSendCeloViaGoldToken(t *testing.T) {
64+
ac := test.AccountConfig(3, 2)
65+
gc, ec, err := test.BuildConfig(ac)
66+
require.NoError(t, err)
67+
network, shutdown, err := test.NewNetwork(ac, gc, ec)
68+
require.NoError(t, err)
69+
defer shutdown()
70+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
71+
defer cancel()
72+
73+
accounts := test.Accounts(ac.DeveloperAccounts(), gc.ChainConfig())
74+
// Send 1 wei of CELO from accounts[0] to accounts[1] by calling GoldToken.transfer
75+
tx, err := accounts[0].SendCeloViaGoldToken(ctx, accounts[1].Address, 1, network[0])
76+
require.NoError(t, err)
77+
78+
// Wait for the whole network to process the transaction.
79+
err = network.AwaitTransactions(ctx, tx)
80+
require.NoError(t, err)
81+
c, err := rpc.DialContext(ctx, network[0].WSEndpoint())
82+
require.NoError(t, err)
83+
84+
var result map[string]interface{}
85+
tracerStr := "callTracer"
86+
err = c.CallContext(ctx, &result, "debug_traceTransaction", tx.Hash().String(), tracers.TraceConfig{Tracer: &tracerStr})
87+
88+
require.NoError(t, err)
89+
// Check top level gas values
90+
require.Equal(t, result["gasUsed"], "0x3a46")
91+
require.Equal(t, result["gas"], "0x3ac4")
92+
}
93+
5894
// This test verifies correct behavior in a network of size one, in the case that
5995
// this fails we know that the problem does not lie with our network code.
6096
func TestSingleNodeNetworkManyTxs(t *testing.T) {

eth/tracers/api_test.go

+189
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"testing"
3030
"time"
3131

32+
"github.com/celo-org/celo-blockchain/accounts/abi"
3233
"github.com/celo-org/celo-blockchain/common"
3334
"github.com/celo-org/celo-blockchain/common/hexutil"
3435
"github.com/celo-org/celo-blockchain/consensus"
@@ -544,6 +545,194 @@ func TestTraceTransactionWithRegistryDeployed(t *testing.T) {
544545
}
545546
}
546547

548+
// Use the callTracer to trace a native CELO transfer after the
549+
// registry has been deployed, as above.
550+
func TestCallTraceTransactionNativeTransfer(t *testing.T) {
551+
t.Parallel()
552+
553+
// Initialize test accounts
554+
accounts := newAccounts(2)
555+
genesis := &core.Genesis{Alloc: core.GenesisAlloc{
556+
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
557+
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
558+
common.HexToAddress("0xce10"): { // Registry Proxy
559+
Code: testutil.RegistryProxyOpcodes,
560+
Storage: map[common.Hash]common.Hash{
561+
// Hashes represent the storage slot for Registry.sol's `registry` mapping
562+
// which is stored in the RegistryProxy's storage.
563+
// Hashes are computed by taking: keccack(packed(params.GoldTokenRegistryId, 1)),
564+
// where 1 is the storage offset)
565+
common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"): common.HexToHash("0xce11"), // Registry Implementation
566+
common.HexToHash("0x91646b8507bf2e54d7c3de9155442ba111546b81af1cbdd1f68eeb6926b98d58"): common.HexToHash("0xd023"), // Governance Proxy
567+
},
568+
Balance: big.NewInt(0),
569+
},
570+
common.HexToAddress("0xce11"): { // Registry Implementation
571+
Code: testutil.RegistryOpcodes,
572+
Balance: big.NewInt(0),
573+
},
574+
}}
575+
576+
target := common.Hash{}
577+
signer := types.HomesteadSigner{}
578+
transferVal := big.NewInt(1000)
579+
api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) {
580+
// Transfer from account[0] to account[1]
581+
// value: 1000 wei
582+
// fee: 0 wei
583+
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, transferVal, params.TxGas, nil, nil, nil, nil, nil), signer, accounts[0].key)
584+
b.AddTx(tx)
585+
target = tx.Hash()
586+
}))
587+
tracerStr := "callTracer"
588+
result, err := api.TraceTransaction(context.Background(), target, &TraceConfig{Tracer: &tracerStr})
589+
if err != nil {
590+
t.Errorf("Failed to trace transaction %v", err)
591+
}
592+
593+
ret := new(callTrace)
594+
if err := json.Unmarshal(result.(json.RawMessage), ret); err != nil {
595+
t.Fatalf("failed to unmarshal trace result: %v", err)
596+
}
597+
expectedTrace := &callTrace{
598+
Type: "CALL",
599+
From: accounts[0].addr,
600+
To: accounts[1].addr,
601+
Input: hexutil.Bytes(common.Hex2Bytes("0x")),
602+
Output: hexutil.Bytes(common.Hex2Bytes("0x")),
603+
Gas: newRPCUint64(0),
604+
GasUsed: newRPCUint64(0),
605+
Value: (*hexutil.Big)(transferVal),
606+
}
607+
if !jsonEqual(ret, expectedTrace) {
608+
t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, expectedTrace)
609+
}
610+
}
611+
612+
// Use the callTracer to trace a CELO transfer made via the transfer
613+
// precompile (by sending this from the registered GoldToken contract).
614+
func TestCallTraceTransactionPrecompileTransfer(t *testing.T) {
615+
// Invoke the transfer precompile by sending a transfer from an account
616+
// registered as GoldToken in the mock registry
617+
t.Parallel()
618+
// Initialize test accounts
619+
accounts := newAccounts(3)
620+
goldToken := accounts[0]
621+
registryProxyAddr := common.HexToAddress("0xce10")
622+
registryImplAddr := common.HexToAddress("0xce11")
623+
genesis := &core.Genesis{Alloc: core.GenesisAlloc{
624+
goldToken.addr: {Balance: big.NewInt(params.Ether)},
625+
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
626+
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
627+
registryProxyAddr: { // Registry Proxy
628+
Code: testutil.RegistryProxyOpcodes,
629+
Storage: map[common.Hash]common.Hash{
630+
common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"): common.HexToHash("0xce11"), // Registry Implementation
631+
common.HexToHash("0x91646b8507bf2e54d7c3de9155442ba111546b81af1cbdd1f68eeb6926b98d58"): common.HexToHash("0xd023"), // Governance Proxy
632+
common.HexToHash("0x773cc8652456781771d48fb3d560d7ba3d6d1882654492b68beec583d2c590aa"): goldToken.addr.Hash(), // GoldToken Implementation
633+
common.HexToHash("0x2131a4338f6fb8d4507e234a7c72af8efefbbf2f1817ed570bce33eb6667feb9"): common.HexToHash("0xd007"), // Reserve Implementation
634+
},
635+
Balance: big.NewInt(0),
636+
},
637+
registryImplAddr: { // Registry Implementation
638+
Code: testutil.RegistryOpcodes,
639+
Balance: big.NewInt(0),
640+
},
641+
}}
642+
643+
target := common.Hash{}
644+
signer := types.HomesteadSigner{}
645+
transferVal := big.NewInt(1000)
646+
647+
// Construct and pack data for transfer precompile representing [from, to, value]
648+
addressTy, err := abi.NewType("address", "", nil)
649+
if err != nil {
650+
t.Fatalf("failed to create address type: %v", err)
651+
}
652+
uint256Ty, err := abi.NewType("uint256", "", nil)
653+
if err != nil {
654+
t.Fatalf("failed to create uint256 type: %v", err)
655+
}
656+
657+
transferArgs := abi.Arguments{
658+
{
659+
Type: addressTy,
660+
},
661+
{
662+
Type: addressTy,
663+
},
664+
{
665+
Type: uint256Ty,
666+
},
667+
}
668+
data, err := transferArgs.Pack(accounts[1].addr, accounts[2].addr, transferVal)
669+
if err != nil {
670+
t.Fatalf("failed to pack args: %v", err)
671+
}
672+
transferPrecompile := common.HexToAddress("0xfd")
673+
gas := params.TxGas * 2
674+
api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) {
675+
// Transfer via transfer precompile by sending tx from GoldToken addr
676+
tx, _ := types.SignTx(types.NewTransaction(uint64(i), transferPrecompile, big.NewInt(0), gas, big.NewInt(3), nil, nil, nil, data), signer, goldToken.key)
677+
b.AddTx(tx)
678+
target = tx.Hash()
679+
}))
680+
tracerStr := "callTracer"
681+
result, err := api.TraceTransaction(context.Background(), target, &TraceConfig{Tracer: &tracerStr})
682+
683+
if err != nil {
684+
t.Errorf("Failed to trace transaction %v", err)
685+
}
686+
687+
ret := new(callTrace)
688+
if err := json.Unmarshal(result.(json.RawMessage), ret); err != nil {
689+
t.Fatalf("failed to unmarshal trace result: %v", err)
690+
}
691+
692+
// Registry ABI packed version of Registry.getAddressFor("GoldToken")
693+
packedGetAddressForGoldToken := common.FromHex("0xdd927233d7e89ade8430819f08bf97a087285824af3351ee12d72a2d132b0c6c0687bfaf")
694+
expectedTrace := &callTrace{
695+
// Outer transaction call
696+
Type: "CALL",
697+
From: goldToken.addr,
698+
To: transferPrecompile,
699+
Input: data,
700+
Output: data,
701+
Gas: newRPCUint64(20112),
702+
// Note that top-level traces do not currently include intrinsic gas
703+
GasUsed: newRPCUint64(params.CallValueTransferGas),
704+
Value: (*hexutil.Big)(big.NewInt(0)),
705+
Calls: []callTrace{
706+
{
707+
// Lookup of GoldToken contract address with capped gas
708+
Type: "STATICCALL",
709+
From: common.ZeroAddress,
710+
To: registryProxyAddr,
711+
Input: packedGetAddressForGoldToken,
712+
Output: common.LeftPadBytes(goldToken.addr.Bytes(), 32),
713+
Gas: newRPCUint64(params.MaxGasForGetAddressFor),
714+
GasUsed: newRPCUint64(0),
715+
Calls: []callTrace{
716+
{
717+
// RegistryProxy -> RegistryImpl delegate call to
718+
// retrieve GoldToken address
719+
Type: "DELEGATECALL",
720+
From: registryProxyAddr,
721+
To: registryImplAddr,
722+
Input: packedGetAddressForGoldToken,
723+
Output: common.LeftPadBytes(goldToken.addr.Bytes(), 32),
724+
Gas: newRPCUint64(0),
725+
GasUsed: newRPCUint64(0),
726+
},
727+
},
728+
},
729+
},
730+
}
731+
if !jsonEqual(ret, expectedTrace) {
732+
t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, expectedTrace)
733+
}
734+
}
735+
547736
func TestTraceBlock(t *testing.T) {
548737
t.Parallel()
549738

0 commit comments

Comments
 (0)