github.com/igggame/nebulas-go@v2.1.0+incompatible/core/transaction_test.go (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package core 20 21 import ( 22 "encoding/json" 23 "fmt" 24 "reflect" 25 "testing" 26 "time" 27 28 "github.com/gogo/protobuf/proto" 29 "github.com/nebulasio/go-nebulas/core/pb" 30 "github.com/nebulasio/go-nebulas/crypto" 31 "github.com/nebulasio/go-nebulas/crypto/hash" 32 "github.com/nebulasio/go-nebulas/crypto/keystore" 33 "github.com/nebulasio/go-nebulas/util" 34 "github.com/nebulasio/go-nebulas/util/byteutils" 35 "github.com/stretchr/testify/assert" 36 ) 37 38 func mockNormalTransaction(chainID uint32, nonce uint64) *Transaction { 39 // payload, _ := NewBinaryPayload(nil).ToBytes() 40 return mockTransaction(chainID, nonce, TxPayloadBinaryType, nil) 41 } 42 43 func mockDeployTransaction(chainID uint32, nonce uint64) *Transaction { 44 source := ` 45 "use strict";var StandardToken=function(){LocalContractStorage.defineProperties(this,{name:null,symbol:null,_totalSupply:null,totalIssued:null});LocalContractStorage.defineMapProperty(this,"balances")};StandardToken.prototype={init:function(name,symbol,totalSupply){this.name=name;this.symbol=symbol;this._totalSupply=totalSupply;this.totalIssued=0},totalSupply:function(){return this._totalSupply},balanceOf:function(owner){return this.balances.get(owner)||0},transfer:function(to,value){var balance=this.balanceOf(msg.sender);if(balance<value){return false}var finalBalance=balance-value;this.balances.set(msg.sender,finalBalance);this.balances.set(to,this.balanceOf(to)+value);return true},pay:function(msg,amount){if(this.totalIssued+amount>this._totalSupply){throw new Error("too much amount, exceed totalSupply")}this.balances.set(msg.sender,this.balanceOf(msg.sender)+amount);this.totalIssued+=amount}};module.exports=StandardToken; 46 ` 47 sourceType := "js" 48 args := `["NebulasToken", "NAS", 1000000000]` 49 payloadObj, _ := NewDeployPayload(source, sourceType, args) 50 payload, _ := payloadObj.ToBytes() 51 return mockTransaction(chainID, nonce, TxPayloadDeployType, payload) 52 } 53 54 func mockCallTransaction(chainID uint32, nonce uint64, function, args string) *Transaction { 55 callpayload, _ := NewCallPayload(function, args) 56 payload, _ := callpayload.ToBytes() 57 return mockTransaction(chainID, nonce, TxPayloadCallType, payload) 58 } 59 60 func mockTransaction(chainID uint32, nonce uint64, payloadType string, payload []byte) *Transaction { 61 from := mockAddress() 62 to := mockAddress() 63 if payloadType == TxPayloadDeployType { 64 to = from 65 } 66 tx, _ := NewTransaction(chainID, from, to, util.NewUint128(), nonce, payloadType, payload, TransactionGasPrice, TransactionMaxGas) 67 return tx 68 } 69 70 func TestTransaction(t *testing.T) { 71 type fields struct { 72 hash byteutils.Hash 73 from *Address 74 to *Address 75 value *util.Uint128 76 nonce uint64 77 timestamp int64 78 alg uint8 79 data *corepb.Data 80 gasPrice *util.Uint128 81 gasLimit *util.Uint128 82 } 83 gasPrice, _ := util.NewUint128FromInt(1) 84 gasLimit, _ := util.NewUint128FromInt(1) 85 tests := []struct { 86 name string 87 fields fields 88 }{ 89 { 90 "full struct", 91 fields(fields{ 92 []byte("123455"), 93 mockAddress(), 94 mockAddress(), 95 util.NewUint128(), 96 456, 97 time.Now().Unix(), 98 uint8(keystore.SECP256K1), 99 &corepb.Data{Type: TxPayloadBinaryType, Payload: []byte("hwllo")}, 100 gasPrice, 101 gasLimit, 102 }), 103 }, 104 } 105 for _, tt := range tests { 106 t.Run(tt.name, func(t *testing.T) { 107 tx := &Transaction{ 108 hash: tt.fields.hash, 109 from: tt.fields.from, 110 to: tt.fields.to, 111 value: tt.fields.value, 112 nonce: tt.fields.nonce, 113 timestamp: tt.fields.timestamp, 114 alg: keystore.Algorithm(tt.fields.alg), 115 data: tt.fields.data, 116 gasPrice: tt.fields.gasPrice, 117 gasLimit: tt.fields.gasLimit, 118 } 119 msg, _ := tx.ToProto() 120 ir, _ := proto.Marshal(msg) 121 ntx := new(Transaction) 122 nMsg := new(corepb.Transaction) 123 proto.Unmarshal(ir, nMsg) 124 ntx.FromProto(nMsg) 125 ntx.timestamp = tx.timestamp 126 if !reflect.DeepEqual(tx, ntx) { 127 t.Errorf("Transaction.Serialize() = %v, want %v", *tx, *ntx) 128 } 129 }) 130 } 131 } 132 133 func TestTransaction_VerifyIntegrity(t *testing.T) { 134 testCount := 3 135 type testTx struct { 136 name string 137 tx *Transaction 138 signer keystore.Signature 139 count int 140 } 141 142 tests := []testTx{} 143 ks := keystore.DefaultKS 144 145 for index := 0; index < testCount; index++ { 146 147 from := mockAddress() 148 to := mockAddress() 149 150 key1, _ := ks.GetUnlocked(from.String()) 151 signature, _ := crypto.NewSignature(keystore.SECP256K1) 152 signature.InitSign(key1.(keystore.PrivateKey)) 153 154 gasLimit, _ := util.NewUint128FromInt(200000) 155 tx, _ := NewTransaction(1, from, to, util.NewUint128(), 10, TxPayloadBinaryType, []byte("datadata"), TransactionGasPrice, gasLimit) 156 157 test := testTx{string(index), tx, signature, 1} 158 tests = append(tests, test) 159 } 160 for _, tt := range tests { 161 for index := 0; index < tt.count; index++ { 162 t.Run(tt.name, func(t *testing.T) { 163 err := tt.tx.Sign(tt.signer) 164 if err != nil { 165 t.Errorf("Sign() error = %v", err) 166 return 167 } 168 err = tt.tx.VerifyIntegrity(tt.tx.chainID) 169 if err != nil { 170 t.Errorf("verify failed:%s", err) 171 return 172 } 173 }) 174 } 175 } 176 } 177 178 func TestTransaction_VerifyExecutionDependency(t *testing.T) { 179 180 neb := testNeb(t) 181 bc := neb.chain 182 183 a := mockAddress() 184 b := mockAddress() 185 c := mockAddress() 186 e := mockAddress() 187 f := mockAddress() 188 189 ks := keystore.DefaultKS 190 191 v, _ := util.NewUint128FromInt(1) 192 tx1, _ := NewTransaction(bc.chainID, a, b, v, uint64(1), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas) 193 tx2, _ := NewTransaction(bc.chainID, a, b, v, uint64(2), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas) 194 tx3, _ := NewTransaction(bc.chainID, b, c, v, uint64(1), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas) 195 tx4, _ := NewTransaction(bc.chainID, e, f, v, uint64(1), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas) 196 197 txs := [4]*Transaction{tx1, tx2, tx3, tx4} 198 for _, tx := range txs { 199 key, _ := ks.GetUnlocked(tx.from.String()) 200 signature, _ := crypto.NewSignature(keystore.SECP256K1) 201 signature.InitSign(key.(keystore.PrivateKey)) 202 assert.Nil(t, tx.Sign(signature)) 203 } 204 205 balance, _ := util.NewUint128FromString("1000000000000000000") 206 207 bc.tailBlock.Begin() 208 { 209 fromAcc, err := bc.tailBlock.worldState.GetOrCreateUserAccount(tx1.from.address) 210 assert.Nil(t, err) 211 fromAcc.AddBalance(balance) 212 } 213 { 214 fromAcc, err := bc.tailBlock.worldState.GetOrCreateUserAccount(tx3.from.address) 215 assert.Nil(t, err) 216 fromAcc.AddBalance(balance) 217 } 218 { 219 fromAcc, err := bc.tailBlock.worldState.GetOrCreateUserAccount(tx4.from.address) 220 assert.Nil(t, err) 221 fromAcc.AddBalance(balance) 222 } 223 224 bc.tailBlock.Commit() 225 226 block, err := bc.NewBlock(bc.tailBlock.header.coinbase) 227 assert.Nil(t, err) 228 block.Begin() 229 230 //tx1 231 txWorldState1, err := block.WorldState().Prepare("1") 232 assert.Nil(t, err) 233 giveback, executionErr := VerifyExecution(tx1, block, txWorldState1) 234 assert.Nil(t, executionErr) 235 assert.False(t, giveback) 236 dependency1, err := txWorldState1.CheckAndUpdate() 237 assert.Nil(t, err) 238 assert.Equal(t, 0, len(dependency1)) 239 240 acc1, err := block.worldState.GetOrCreateUserAccount(tx1.from.address) 241 assert.Equal(t, "999999999999999999", acc1.Balance().String()) 242 toacc1, err := block.worldState.GetOrCreateUserAccount(tx1.to.address) 243 assert.Equal(t, "1000000000000000001", toacc1.Balance().String()) 244 245 //tx2 246 txWorldState2, err := block.WorldState().Prepare("2") 247 txWorldState3, err := block.WorldState().Prepare("3") 248 txWorldState4, err := block.WorldState().Prepare("4") 249 250 giveback, executionErr2 := VerifyExecution(tx2, block, txWorldState2) 251 assert.Nil(t, executionErr2) 252 assert.False(t, giveback) 253 dependency2, err := txWorldState2.CheckAndUpdate() 254 assert.Nil(t, err) 255 assert.Equal(t, 1, len(dependency2)) 256 assert.Equal(t, "1", dependency2[0]) 257 acc2, err := block.worldState.GetOrCreateUserAccount(tx2.from.address) 258 assert.Equal(t, "999999999999999998", acc2.Balance().String()) 259 toacc2, err := block.worldState.GetOrCreateUserAccount(tx2.to.address) 260 assert.Equal(t, "1000000000000000002", toacc2.Balance().String()) 261 262 // tx3 263 giveback, executionErr3 := VerifyExecution(tx3, block, txWorldState3) 264 assert.NotNil(t, executionErr3) 265 assert.True(t, giveback) 266 txWorldState3.Close() 267 268 //tx4 269 giveback, executionErr4 := VerifyExecution(tx4, block, txWorldState4) 270 assert.Nil(t, executionErr4) 271 assert.False(t, giveback) 272 _, err4 := txWorldState4.CheckAndUpdate() 273 assert.Nil(t, err4) 274 275 txWorldState3, err = block.WorldState().Prepare("3") 276 assert.Nil(t, err) 277 giveback, executionErr3 = VerifyExecution(tx3, block, txWorldState3) 278 assert.Nil(t, executionErr3) 279 assert.False(t, giveback) 280 dependency3, err := txWorldState3.CheckAndUpdate() 281 assert.Nil(t, err) 282 assert.Equal(t, 1, len(dependency3)) 283 assert.Equal(t, "2", dependency3[0]) 284 285 acc3, err := block.worldState.GetOrCreateUserAccount(tx3.from.address) 286 assert.Equal(t, "1000000000000000001", acc3.Balance().String()) 287 toacc3, err := block.worldState.GetOrCreateUserAccount(tx3.to.address) 288 assert.Equal(t, "1", toacc3.Balance().String()) 289 290 assert.Nil(t, block.Seal()) 291 } 292 293 func TestTransaction_VerifyExecution(t *testing.T) { 294 type testTx struct { 295 name string 296 tx *Transaction 297 fromBalance *util.Uint128 298 gasUsed *util.Uint128 299 wanted error 300 afterBalance *util.Uint128 301 toBalance *util.Uint128 302 coinbaseBalance *util.Uint128 303 status int 304 eventErr string 305 giveback bool 306 } 307 tests := []testTx{} 308 309 neb := testNeb(t) 310 bc := neb.chain 311 312 // 1NAS = 10^18 313 balance, _ := util.NewUint128FromString("1000000000000000000") 314 // normal tx 315 normalTx := mockNormalTransaction(bc.chainID, 0) 316 normalTx.value, _ = util.NewUint128FromInt(1000000) 317 gasConsume, err := normalTx.gasPrice.Mul(MinGasCountPerTransaction) 318 assert.Nil(t, err) 319 afterBalance, err := balance.Sub(gasConsume) 320 assert.Nil(t, err) 321 afterBalance, err = afterBalance.Sub(normalTx.value) 322 coinbaseBalance, err := normalTx.gasPrice.Mul(MinGasCountPerTransaction) 323 assert.Nil(t, err) 324 tests = append(tests, testTx{ 325 name: "normal tx", 326 tx: normalTx, 327 fromBalance: balance, 328 gasUsed: MinGasCountPerTransaction, 329 afterBalance: afterBalance, 330 toBalance: normalTx.value, 331 coinbaseBalance: coinbaseBalance, 332 wanted: nil, 333 eventErr: "", 334 status: 1, 335 giveback: false, 336 }) 337 338 // contract deploy tx 339 deployTx := mockDeployTransaction(bc.chainID, 0) 340 deployTx.value = util.NewUint128() 341 gasUsed, _ := util.NewUint128FromInt(21203) 342 coinbaseBalance, err = deployTx.gasPrice.Mul(gasUsed) 343 assert.Nil(t, err) 344 balanceConsume, err := deployTx.gasPrice.Mul(gasUsed) 345 assert.Nil(t, err) 346 afterBalance, err = balance.Sub(balanceConsume) 347 assert.Nil(t, err) 348 tests = append(tests, testTx{ 349 name: "contract deploy tx", 350 tx: deployTx, 351 fromBalance: balance, 352 gasUsed: gasUsed, 353 afterBalance: afterBalance, 354 toBalance: afterBalance, 355 coinbaseBalance: coinbaseBalance, 356 wanted: nil, 357 eventErr: "", 358 status: 1, 359 giveback: false, 360 }) 361 362 // contract call tx 363 callTx := mockCallTransaction(bc.chainID, 1, "totalSupply", "") 364 callTx.value = util.NewUint128() 365 gasUsed, _ = util.NewUint128FromInt(20096) 366 coinbaseBalance, err = callTx.gasPrice.Mul(gasUsed) 367 assert.Nil(t, err) 368 balanceConsume, err = callTx.gasPrice.Mul(gasUsed) 369 assert.Nil(t, err) 370 afterBalance, err = balance.Sub(balanceConsume) 371 372 tests = append(tests, testTx{ 373 name: "contract call tx", 374 tx: callTx, 375 fromBalance: balance, 376 gasUsed: gasUsed, 377 afterBalance: afterBalance, 378 toBalance: callTx.value, 379 coinbaseBalance: coinbaseBalance, 380 wanted: nil, 381 eventErr: ErrContractCheckFailed.Error(), 382 status: 0, 383 giveback: false, 384 }) 385 386 // normal tx insufficient fromBalance before execution 387 insufficientBlanceTx := mockNormalTransaction(bc.chainID, 0) 388 insufficientBlanceTx.value = util.NewUint128() 389 tests = append(tests, testTx{ 390 name: "normal tx insufficient fromBalance", 391 tx: insufficientBlanceTx, 392 fromBalance: util.NewUint128(), 393 gasUsed: util.Uint128Zero(), 394 afterBalance: util.NewUint128(), 395 toBalance: util.NewUint128(), 396 wanted: ErrInsufficientBalance, 397 status: 0, 398 giveback: false, 399 }) 400 401 // normal tx out of gasLimit 402 outOfGasLimitTx := mockNormalTransaction(bc.chainID, 0) 403 outOfGasLimitTx.value = util.NewUint128() 404 outOfGasLimitTx.gasLimit, _ = util.NewUint128FromInt(1) 405 tests = append(tests, testTx{ 406 name: "normal tx out of gasLimit", 407 tx: outOfGasLimitTx, 408 fromBalance: balance, 409 gasUsed: util.Uint128Zero(), 410 afterBalance: balance, 411 toBalance: util.NewUint128(), 412 wanted: ErrOutOfGasLimit, 413 status: 0, 414 giveback: false, 415 }) 416 417 // tx payload load err 418 payloadErrTx := mockDeployTransaction(bc.chainID, 0) 419 payloadErrTx.value = util.NewUint128() 420 payloadErrTx.data.Payload = []byte("0x00") 421 gasCountOfTxBase, err := payloadErrTx.GasCountOfTxBase() 422 assert.Nil(t, err) 423 coinbaseBalance, err = payloadErrTx.gasPrice.Mul(gasCountOfTxBase) 424 assert.Nil(t, err) 425 balanceConsume, err = payloadErrTx.gasPrice.Mul(gasCountOfTxBase) 426 assert.Nil(t, err) 427 afterBalance, err = balance.Sub(balanceConsume) 428 assert.Nil(t, err) 429 getUsed, err := payloadErrTx.GasCountOfTxBase() 430 assert.Nil(t, err) 431 tests = append(tests, testTx{ 432 name: "payload error tx", 433 tx: payloadErrTx, 434 fromBalance: balance, 435 gasUsed: getUsed, 436 afterBalance: afterBalance, 437 toBalance: afterBalance, 438 coinbaseBalance: coinbaseBalance, 439 wanted: nil, 440 eventErr: "invalid argument(s)", 441 status: 0, 442 giveback: false, 443 }) 444 445 // tx execution err 446 executionErrTx := mockCallTransaction(bc.chainID, 0, "test", "") 447 executionErrTx.value = util.NewUint128() 448 result, err := bc.SimulateTransactionExecution(executionErrTx) 449 assert.Nil(t, err) 450 assert.Equal(t, ErrContractCheckFailed, result.Err) 451 coinbaseBalance, err = executionErrTx.gasPrice.Mul(result.GasUsed) 452 assert.Nil(t, err) 453 balanceConsume, err = executionErrTx.gasPrice.Mul(result.GasUsed) 454 assert.Nil(t, err) 455 afterBalance, err = balance.Sub(balanceConsume) 456 assert.Nil(t, err) 457 458 tests = append(tests, testTx{ 459 name: "execution err tx", 460 tx: executionErrTx, 461 fromBalance: balance, 462 gasUsed: result.GasUsed, 463 afterBalance: afterBalance, 464 toBalance: util.NewUint128(), 465 coinbaseBalance: coinbaseBalance, 466 wanted: nil, 467 eventErr: ErrContractCheckFailed.Error(), 468 status: 0, 469 giveback: false, 470 }) 471 472 // tx execution insufficient fromBalance after execution 473 executionInsufficientBalanceTx := mockDeployTransaction(bc.chainID, 0) 474 executionInsufficientBalanceTx.value = balance 475 gasUsed, _ = util.NewUint128FromInt(21103) 476 coinbaseBalance, err = executionInsufficientBalanceTx.gasPrice.Mul(gasUsed) 477 assert.Nil(t, err) 478 balanceConsume, err = executionInsufficientBalanceTx.gasPrice.Mul(gasUsed) 479 assert.Nil(t, err) 480 afterBalance, err = balance.Sub(balanceConsume) 481 assert.Nil(t, err) 482 tests = append(tests, testTx{ 483 name: "execution insufficient fromBalance after execution tx", 484 tx: executionInsufficientBalanceTx, 485 fromBalance: balance, 486 gasUsed: gasUsed, 487 afterBalance: afterBalance, 488 toBalance: afterBalance, 489 coinbaseBalance: coinbaseBalance, 490 wanted: nil, 491 eventErr: ErrInsufficientBalance.Error(), 492 status: 0, 493 giveback: false, 494 }) 495 496 // tx execution equal fromBalance after execution 497 executionEqualBalanceTx := mockDeployTransaction(bc.chainID, 0) 498 result, err = bc.SimulateTransactionExecution(executionEqualBalanceTx) 499 assert.Nil(t, err) 500 assert.Equal(t, ErrInsufficientBalance, result.Err) 501 executionEqualBalanceTx.gasLimit = result.GasUsed 502 t.Log("gasUsed:", result.GasUsed) 503 coinbaseBalance, err = executionInsufficientBalanceTx.gasPrice.Mul(result.GasUsed) 504 assert.Nil(t, err) 505 executionEqualBalanceTx.value = balance 506 gasCost, err := executionEqualBalanceTx.gasPrice.Mul(result.GasUsed) 507 assert.Nil(t, err) 508 fromBalance, err := gasCost.Add(balance) 509 assert.Nil(t, err) 510 tests = append(tests, testTx{ 511 name: "execution equal fromBalance after execution tx", 512 tx: executionEqualBalanceTx, 513 fromBalance: fromBalance, 514 gasUsed: result.GasUsed, 515 afterBalance: balance, 516 toBalance: balance, 517 coinbaseBalance: coinbaseBalance, 518 wanted: nil, 519 eventErr: "", 520 status: 1, 521 giveback: false, 522 }) 523 524 ks := keystore.DefaultKS 525 for _, tt := range tests { 526 t.Run(tt.name, func(t *testing.T) { 527 key, _ := ks.GetUnlocked(tt.tx.from.String()) 528 signature, _ := crypto.NewSignature(keystore.SECP256K1) 529 signature.InitSign(key.(keystore.PrivateKey)) 530 531 err := tt.tx.Sign(signature) 532 assert.Nil(t, err) 533 534 block, err := bc.NewBlock(mockAddress()) 535 block.Begin() 536 fromAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.from.address) 537 assert.Nil(t, err) 538 fromAcc.AddBalance(tt.fromBalance) 539 block.Commit() 540 541 block, err = bc.NewBlockFromParent(bc.tailBlock.header.coinbase, block) 542 assert.Nil(t, err) 543 block.Begin() 544 545 txWorldState, err := block.WorldState().Prepare(tt.tx.Hash().String()) 546 assert.Nil(t, err) 547 548 giveback, executionErr := VerifyExecution(tt.tx, block, txWorldState) 549 assert.Equal(t, tt.wanted, executionErr) 550 assert.Equal(t, giveback, tt.giveback) 551 fromAcc, err = txWorldState.GetOrCreateUserAccount(tt.tx.from.address) 552 assert.Nil(t, err) 553 fmt.Println(fromAcc.Balance().String()) 554 555 txWorldState.CheckAndUpdate() 556 assert.Nil(t, block.rewardCoinbaseForGas()) 557 block.Commit() 558 559 fromAcc, err = block.worldState.GetOrCreateUserAccount(tt.tx.from.address) 560 assert.Nil(t, err) 561 toAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.to.address) 562 assert.Nil(t, err) 563 coinbaseAcc, err := block.worldState.GetOrCreateUserAccount(block.header.coinbase.address) 564 assert.Nil(t, err) 565 566 if tt.afterBalance != nil { 567 assert.Equal(t, tt.afterBalance.String(), fromAcc.Balance().String()) 568 } 569 if tt.toBalance != nil { 570 assert.Equal(t, tt.toBalance, toAcc.Balance()) 571 } 572 if tt.coinbaseBalance != nil { 573 coinbaseBalance, err := tt.coinbaseBalance.Add(BlockReward) 574 assert.Nil(t, err) 575 assert.Equal(t, coinbaseBalance, coinbaseAcc.Balance()) 576 } 577 578 events, _ := block.worldState.FetchEvents(tt.tx.hash) 579 580 for _, v := range events { 581 if v.Topic == TopicTransactionExecutionResult { 582 txEvent := TransactionEvent{} 583 json.Unmarshal([]byte(v.Data), &txEvent) 584 status := int(txEvent.Status) 585 assert.Equal(t, tt.status, status) 586 assert.Equal(t, tt.eventErr, txEvent.Error) 587 assert.Equal(t, tt.gasUsed.String(), txEvent.GasUsed) 588 break 589 } 590 } 591 }) 592 } 593 } 594 595 func TestTransaction_SimulateExecution(t *testing.T) { 596 type testCase struct { 597 name string 598 tx *Transaction 599 gasUsed *util.Uint128 600 result string 601 wanted error 602 } 603 604 tests := []testCase{} 605 606 neb := testNeb(t) 607 bc := neb.chain 608 609 normalTx := mockNormalTransaction(bc.chainID, 0) 610 normalTx.value, _ = util.NewUint128FromInt(1000000) 611 tests = append(tests, testCase{ 612 name: "normal tx", 613 tx: normalTx, 614 gasUsed: MinGasCountPerTransaction, 615 result: "", 616 wanted: ErrInsufficientBalance, 617 }) 618 619 deployTx := mockDeployTransaction(bc.chainID, 0) 620 deployTx.to = deployTx.from 621 deployTx.value = util.NewUint128() 622 gasUsed, _ := util.NewUint128FromInt(21203) 623 tests = append(tests, testCase{ 624 name: "contract deploy tx", 625 tx: deployTx, 626 gasUsed: gasUsed, 627 result: "", 628 wanted: ErrInsufficientBalance, 629 }) 630 631 // contract call tx 632 callTx := mockCallTransaction(bc.chainID, 1, "totalSupply", "") 633 callTx.value = util.NewUint128() 634 gasUsed, _ = util.NewUint128FromInt(20096) 635 tests = append(tests, testCase{ 636 name: "contract call tx", 637 tx: callTx, 638 gasUsed: gasUsed, 639 result: "", 640 wanted: ErrContractCheckFailed, 641 }) 642 643 for _, tt := range tests { 644 t.Run(tt.name, func(t *testing.T) { 645 block, err := bc.NewBlock(bc.tailBlock.header.coinbase) 646 assert.Nil(t, err) 647 648 fromAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.from.address) 649 assert.Nil(t, err) 650 fromBefore := fromAcc.Balance() 651 652 toAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.to.address) 653 assert.Nil(t, err) 654 toBefore := toAcc.Balance() 655 656 coinbaseAcc, err := block.worldState.GetOrCreateUserAccount(block.header.coinbase.address) 657 assert.Nil(t, err) 658 coinbaseBefore := coinbaseAcc.Balance() 659 660 result, err := tt.tx.simulateExecution(block) 661 662 assert.Equal(t, tt.wanted, result.Err) 663 assert.Equal(t, tt.result, result.Msg) 664 assert.Equal(t, tt.gasUsed, result.GasUsed) 665 assert.Nil(t, err) 666 667 fromAcc, err = block.worldState.GetOrCreateUserAccount(tt.tx.from.address) 668 assert.Nil(t, err) 669 assert.Equal(t, fromBefore, fromAcc.Balance()) 670 671 toAcc, err = block.worldState.GetOrCreateUserAccount(tt.tx.to.address) 672 assert.Nil(t, err) 673 assert.Equal(t, toBefore, toAcc.Balance()) 674 675 coinbaseAcc, err = block.worldState.GetOrCreateUserAccount(block.header.coinbase.address) 676 assert.Nil(t, err) 677 assert.Equal(t, coinbaseBefore, coinbaseAcc.Balance()) 678 679 block.Seal() 680 }) 681 } 682 } 683 684 func TestDeployAndCall(t *testing.T) { 685 neb := testNeb(t) 686 bc := neb.chain 687 688 coinbase := mockAddress() 689 from := mockAddress() 690 balance, _ := util.NewUint128FromString("1000000000000000000") 691 692 ks := keystore.DefaultKS 693 key, _ := ks.GetUnlocked(from.String()) 694 signature, _ := crypto.NewSignature(keystore.SECP256K1) 695 signature.InitSign(key.(keystore.PrivateKey)) 696 697 block, err := bc.NewBlock(coinbase) 698 fromAcc, err := block.worldState.GetOrCreateUserAccount(from.address) 699 assert.Nil(t, err) 700 fromAcc.AddBalance(balance) 701 block.Commit() 702 703 // contract deploy tx 704 deployTx := mockDeployTransaction(bc.chainID, 0) 705 deployTx.from = from 706 deployTx.to = from 707 deployTx.value = util.NewUint128() 708 deployTx.Sign(signature) 709 710 // contract call tx 711 callTx := mockCallTransaction(bc.chainID, 1, "totalSupply", "") 712 callTx.from = from 713 callTx.to, _ = deployTx.GenerateContractAddress() 714 callTx.value = util.NewUint128() 715 callTx.Sign(signature) 716 717 assert.Nil(t, err) 718 719 block, err = bc.NewBlockFromParent(bc.tailBlock.header.coinbase, block) 720 assert.Nil(t, err) 721 722 txWorldState, err := block.WorldState().Prepare(deployTx.Hash().String()) 723 assert.Nil(t, err) 724 giveback, err := VerifyExecution(deployTx, block, txWorldState) 725 assert.False(t, giveback) 726 assert.Nil(t, err) 727 giveback, err = AcceptTransaction(deployTx, txWorldState) 728 assert.False(t, giveback) 729 assert.Nil(t, err) 730 _, err = txWorldState.CheckAndUpdate() 731 assert.Nil(t, err) 732 733 deployEvents, _ := block.worldState.FetchEvents(deployTx.Hash()) 734 assert.Equal(t, len(deployEvents), 1) 735 event := deployEvents[0] 736 if event.Topic == TopicTransactionExecutionResult { 737 txEvent := TransactionEvent{} 738 json.Unmarshal([]byte(event.Data), &txEvent) 739 status := int(txEvent.Status) 740 assert.Equal(t, status, TxExecutionSuccess) 741 } 742 743 txWorldState, err = block.WorldState().Prepare(callTx.Hash().String()) 744 assert.Nil(t, err) 745 giveback, err = VerifyExecution(callTx, block, txWorldState) 746 assert.False(t, giveback) 747 assert.Nil(t, err) 748 giveback, err = AcceptTransaction(callTx, txWorldState) 749 assert.False(t, giveback) 750 assert.Nil(t, err) 751 _, err = txWorldState.CheckAndUpdate() 752 assert.Nil(t, err) 753 754 block.Commit() 755 756 callEvents, _ := block.worldState.FetchEvents(callTx.Hash()) 757 assert.Equal(t, len(callEvents), 1) 758 event = callEvents[0] 759 if event.Topic == TopicTransactionExecutionResult { 760 txEvent := TransactionEvent{} 761 json.Unmarshal([]byte(event.Data), &txEvent) 762 status := int(txEvent.Status) 763 assert.Equal(t, status, TxExecutionSuccess) 764 } 765 } 766 767 func Test1(t *testing.T) { 768 fmt.Println(len(hash.Sha3256([]byte("abc")))) 769 } 770 func TestTransactionString(t *testing.T) { 771 neb := testNeb(t) 772 bc := neb.chain 773 774 a := mockAddress() 775 b := mockAddress() 776 777 v, _ := util.NewUint128FromInt(1) 778 data := `{"Function":"donation","Args":"[\"d\"]"}", "type":"call"}` 779 tx1, _ := NewTransaction(bc.chainID, a, b, v, uint64(1), TxPayloadDeployType, []byte(data), TransactionGasPrice, TransactionMaxGas) 780 expectedOut := fmt.Sprintf(`{"chainID":100,"data":"{\"Function\":\"donation\",\"Args\":\"[\\\"d\\\"]\"}\", \"type\":\"call\"}","from":"%s","gaslimit":"50000000000","gasprice":"1000000","hash":"","nonce":1,"timestamp":%d,"to":"%s","type":"deploy","value":"1"}`, a, tx1.timestamp, b) 781 782 if tx1.String() == tx1.JSONString() { 783 t.Errorf("tx String() != tx.JsonString") 784 } 785 786 if tx1.JSONString() != expectedOut { 787 fmt.Println(tx1.JSONString()) 788 fmt.Println(expectedOut) 789 t.Errorf("tx JsonString() is not working as xpected") 790 } 791 }