@@ -16,16 +16,18 @@ import (
16
16
"github.com/stretchr/testify/require"
17
17
18
18
"github.com/iotexproject/go-pkgs/hash"
19
+ "github.com/iotexproject/iotex-address/address"
20
+
19
21
"github.com/iotexproject/iotex-core/action"
20
22
"github.com/iotexproject/iotex-core/action/protocol"
23
+ accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
21
24
"github.com/iotexproject/iotex-core/action/protocol/rewarding"
22
- "github.com/iotexproject/iotex-core/action/protocol/rolldpos "
25
+ "github.com/iotexproject/iotex-core/blockchain/block "
23
26
"github.com/iotexproject/iotex-core/config"
24
- "github.com/iotexproject/iotex-core/db/batch"
25
27
"github.com/iotexproject/iotex-core/state"
26
28
"github.com/iotexproject/iotex-core/test/identityset"
27
- "github.com/iotexproject/iotex-core/test/mock/mock_chainmanager"
28
29
"github.com/iotexproject/iotex-core/testutil"
30
+ "github.com/iotexproject/iotex-core/testutil/testdb"
29
31
"github.com/iotexproject/iotex-proto/golang/iotextypes"
30
32
)
31
33
@@ -46,153 +48,119 @@ func TestProtocol_HandleTransfer(t *testing.T) {
46
48
47
49
ctrl := gomock .NewController (t )
48
50
defer ctrl .Finish ()
51
+ sm := testdb .NewMockStateManager (ctrl )
49
52
50
- cfg := config .Default
51
- ctx := context .Background ()
52
- sm := mock_chainmanager .NewMockStateManager (ctrl )
53
- cb := batch .NewCachedBatch ()
54
- sm .EXPECT ().State (gomock .Any (), gomock .Any ()).DoAndReturn (
55
- func (account interface {}, opts ... protocol.StateOption ) (uint64 , error ) {
56
- cfg , err := protocol .CreateStateConfig (opts ... )
57
- if err != nil {
58
- return 0 , err
59
- }
60
- val , err := cb .Get ("state" , cfg .Key )
61
- if err != nil {
62
- return 0 , state .ErrStateNotExist
63
- }
64
- return 0 , state .Deserialize (account , val )
65
- }).AnyTimes ()
66
- sm .EXPECT ().PutState (gomock .Any (), gomock .Any ()).DoAndReturn (
67
- func (account interface {}, opts ... protocol.StateOption ) (uint64 , error ) {
68
- cfg , err := protocol .CreateStateConfig (opts ... )
69
- if err != nil {
70
- return 0 , err
71
- }
72
- ss , err := state .Serialize (account )
73
- if err != nil {
74
- return 0 , err
75
- }
76
- cb .Put ("state" , cfg .Key , ss , "failed to put state" )
77
- return 0 , nil
78
- }).AnyTimes ()
79
-
53
+ // set-up protocol and genesis states
80
54
p := NewProtocol (rewarding .DepositGas )
81
55
reward := rewarding .NewProtocol (0 , 0 )
82
56
registry := protocol .NewRegistry ()
83
57
require .NoError (reward .Register (registry ))
84
- rp := rolldpos .NewProtocol (1 , 1 , 1 )
85
- require .NoError (rp .Register (registry ))
86
- cfg .Genesis .Rewarding .InitBalanceStr = "0"
87
- cfg .Genesis .Rewarding .BlockRewardStr = "0"
88
- cfg .Genesis .Rewarding .EpochRewardStr = "0"
89
- cfg .Genesis .Rewarding .NumDelegatesForEpochReward = 1
90
- cfg .Genesis .Rewarding .ExemptAddrStrsFromEpochReward = []string {}
91
- cfg .Genesis .Rewarding .FoundationBonusStr = "0"
92
- cfg .Genesis .Rewarding .NumDelegatesForFoundationBonus = 0
93
- cfg .Genesis .Rewarding .FoundationBonusLastEpoch = 0
94
- cfg .Genesis .Rewarding .ProductivityThreshold = 0
95
- ctx = protocol .WithBlockchainCtx (
96
- protocol .WithRegistry (ctx , registry ),
97
- protocol.BlockchainCtx {
98
- Genesis : cfg .Genesis ,
99
- },
100
- )
101
- ctx = protocol .WithBlockCtx (ctx ,
102
- protocol.BlockCtx {
103
- BlockHeight : 0 ,
104
- Producer : identityset .Address (27 ),
105
- GasLimit : testutil .TestGasLimit ,
106
- })
107
- ctx = protocol .WithActionCtx (ctx ,
108
- protocol.ActionCtx {
109
- Caller : identityset .Address (28 ),
110
- })
111
- require .NoError (
112
- reward .CreateGenesisStates (
113
- ctx ,
114
- sm ,
115
- ),
58
+ chainCtx := protocol .WithBlockchainCtx (
59
+ protocol .WithRegistry (context .Background (), registry ),
60
+ protocol.BlockchainCtx {Genesis : config .Default .Genesis },
116
61
)
117
-
118
- accountAlfa := state.Account {
62
+ ctx := protocol .WithBlockCtx (chainCtx , protocol.BlockCtx {})
63
+ require .NoError (reward .CreateGenesisStates (ctx , sm ))
64
+
65
+ // initial deposit to alfa and charlie (as a contract)
66
+ alfa := identityset .Address (28 )
67
+ bravo := identityset .Address (29 )
68
+ charlie := identityset .Address (30 )
69
+ require .NoError (accountutil .StoreAccount (sm , alfa , & state.Account {
119
70
Balance : big .NewInt (50005 ),
120
- }
121
- accountBravo := state.Account {}
122
- accountCharlie := state.Account {}
123
- pubKeyAlfa := hash .BytesToHash160 (identityset .Address (28 ).Bytes ())
124
- pubKeyBravo := hash .BytesToHash160 (identityset .Address (29 ).Bytes ())
125
- pubKeyCharlie := hash .BytesToHash160 (identityset .Address (30 ).Bytes ())
126
-
127
- _ , err := sm .PutState (& accountAlfa , protocol .LegacyKeyOption (pubKeyAlfa ))
128
- require .NoError (err )
129
- _ , err = sm .PutState (& accountBravo , protocol .LegacyKeyOption (pubKeyBravo ))
130
- require .NoError (err )
131
- _ , err = sm .PutState (& accountCharlie , protocol .LegacyKeyOption (pubKeyCharlie ))
132
- require .NoError (err )
133
-
134
- transfer , err := action .NewTransfer (
135
- uint64 (1 ),
136
- big .NewInt (2 ),
137
- identityset .Address (29 ).String (),
138
- []byte {},
139
- uint64 (10000 ),
140
- big .NewInt (1 ),
141
- )
142
- require .NoError (err )
143
- gas , err := transfer .IntrinsicGas ()
144
- require .NoError (err )
145
-
146
- ctx = protocol .WithActionCtx (context .Background (), protocol.ActionCtx {
147
- Caller : identityset .Address (28 ),
148
- IntrinsicGas : gas ,
149
- })
150
- ctx = protocol .WithBlockCtx (ctx , protocol.BlockCtx {
151
- BlockHeight : 1 ,
152
- Producer : identityset .Address (27 ),
153
- GasLimit : testutil .TestGasLimit ,
154
- })
155
- ctx = protocol .WithBlockchainCtx (
156
- protocol .WithRegistry (ctx , registry ),
157
- protocol.BlockchainCtx {
158
- Genesis : cfg .Genesis ,
71
+ }))
72
+ require .NoError (accountutil .StoreAccount (sm , charlie , & state.Account {
73
+ CodeHash : []byte ("codeHash" ),
74
+ }))
75
+
76
+ tests := []struct {
77
+ caller address.Address
78
+ nonce uint64
79
+ amount * big.Int
80
+ recipient string
81
+ gasLimit uint64
82
+ gasPrice * big.Int
83
+ isContract bool
84
+ err error
85
+ status uint64
86
+ contractLog uint64
87
+ }{
88
+ {
89
+ alfa , 1 , big .NewInt (2 ), bravo .String (), 10000 , big .NewInt (1 ), false , nil , uint64 (iotextypes .ReceiptStatus_Success ), 1 ,
159
90
},
160
- )
91
+ // transfer to contract address only charges gas fee
92
+ {
93
+ alfa , 2 , big .NewInt (20 ), charlie .String (), 10000 , big .NewInt (1 ), true , nil , uint64 (iotextypes .ReceiptStatus_Failure ), 0 ,
94
+ },
95
+ // not enough balance
96
+ {
97
+ alfa , 3 , big .NewInt (30000 ), bravo .String (), 10000 , big .NewInt (1 ), false , state .ErrNotEnoughBalance , uint64 (iotextypes .ReceiptStatus_Failure ), 0 ,
98
+ },
99
+ }
161
100
162
- receipt , err := p .Handle (ctx , transfer , sm )
163
- require .NoError (err )
164
- require .Equal (uint64 (iotextypes .ReceiptStatus_Success ), receipt .Status )
101
+ for _ , v := range tests {
102
+ tsf , err := action .NewTransfer (v .nonce , v .amount , v .recipient , []byte {}, v .gasLimit , v .gasPrice )
103
+ require .NoError (err )
104
+ gas , err := tsf .IntrinsicGas ()
105
+ require .NoError (err )
165
106
166
- var acct state.Account
167
- _ , err = sm .State (& acct , protocol .LegacyKeyOption (pubKeyAlfa ))
168
- require .NoError (err )
169
- require .Equal ("40003" , acct .Balance .String ())
170
- require .Equal (uint64 (1 ), acct .Nonce )
171
- _ , err = sm .State (& acct , protocol .LegacyKeyOption (pubKeyBravo ))
172
- require .NoError (err )
173
- require .Equal ("2" , acct .Balance .String ())
107
+ ctx = protocol .WithActionCtx (chainCtx , protocol.ActionCtx {
108
+ Caller : v .caller ,
109
+ IntrinsicGas : gas ,
110
+ })
111
+ ctx = protocol .WithBlockCtx (ctx , protocol.BlockCtx {
112
+ BlockHeight : 1 ,
113
+ Producer : identityset .Address (27 ),
114
+ GasLimit : testutil .TestGasLimit ,
115
+ })
174
116
175
- contractAcct := state.Account {
176
- CodeHash : []byte ("codeHash" ),
117
+ sender , err := accountutil .AccountState (sm , v .caller .String ())
118
+ require .NoError (err )
119
+ recipient , err := accountutil .AccountState (sm , v .recipient )
120
+ require .NoError (err )
121
+ gasFee := new (big.Int ).Mul (v .gasPrice , new (big.Int ).SetUint64 (gas ))
122
+
123
+ receipt , err := p .Handle (ctx , tsf , sm )
124
+ require .Equal (v .err , errors .Cause (err ))
125
+ if err != nil {
126
+ require .Nil (receipt )
127
+ // sender balance/nonce remains the same in case of error
128
+ newSender , err := accountutil .AccountState (sm , v .caller .String ())
129
+ require .NoError (err )
130
+ require .Equal (sender .Balance , newSender .Balance )
131
+ require .Equal (sender .Nonce , newSender .Nonce )
132
+ continue
133
+ }
134
+ require .Equal (v .status , receipt .Status )
135
+
136
+ // amount is transferred only upon success and for non-contract recipient
137
+ if receipt .Status == uint64 (iotextypes .ReceiptStatus_Success ) && ! v .isContract {
138
+ gasFee .Add (gasFee , v .amount )
139
+ // verify recipient
140
+ newRecipient , err := accountutil .AccountState (sm , v .recipient )
141
+ require .NoError (err )
142
+ recipient .AddBalance (v .amount )
143
+ require .Equal (recipient .Balance , newRecipient .Balance )
144
+ }
145
+ // verify sender balance/nonce
146
+ newSender , err := accountutil .AccountState (sm , v .caller .String ())
147
+ require .NoError (err )
148
+ sender .SubBalance (gasFee )
149
+ require .Equal (sender .Balance , newSender .Balance )
150
+ require .Equal (v .nonce , newSender .Nonce )
151
+
152
+ // verify transaction log
153
+ tLog := block .ReceiptTransactionLog (receipt )
154
+ if tLog != nil {
155
+ require .NotNil (tLog )
156
+ pbLog := tLog .Proto ()
157
+ require .Equal (tsf .Hash (), hash .BytesToHash256 (pbLog .ActionHash ))
158
+ require .EqualValues (v .contractLog , pbLog .NumTransactions )
159
+ rec := pbLog .Transactions [0 ]
160
+ require .Equal (v .amount .String (), rec .Amount )
161
+ require .Equal (v .caller .String (), rec .Sender )
162
+ require .Equal (v .recipient , rec .Recipient )
163
+ require .Equal (iotextypes .TransactionLogType_NATIVE_TRANSFER , rec .Type )
164
+ }
177
165
}
178
- contractAddr := hash .BytesToHash160 (identityset .Address (32 ).Bytes ())
179
- _ , err = sm .PutState (& contractAcct , protocol .LegacyKeyOption (contractAddr ))
180
- require .NoError (err )
181
- transfer , err = action .NewTransfer (
182
- uint64 (2 ),
183
- big .NewInt (3 ),
184
- identityset .Address (32 ).String (),
185
- []byte {},
186
- uint64 (10000 ),
187
- big .NewInt (2 ),
188
- )
189
- require .NoError (err )
190
- // Assume that the gas of this transfer is the same as previous one
191
- receipt , err = p .Handle (ctx , transfer , sm )
192
- require .NoError (err )
193
- require .Equal (uint64 (iotextypes .ReceiptStatus_Failure ), receipt .Status )
194
- _ , err = sm .State (& acct , protocol .LegacyKeyOption (pubKeyAlfa ))
195
- require .NoError (err )
196
- require .Equal (uint64 (2 ), acct .Nonce )
197
- require .Equal ("20003" , acct .Balance .String ())
198
166
}
0 commit comments