gitlab.com/flarenetwork/coreth@v0.1.1/chain/multicoin_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 12 // See the file LICENSE for licensing terms. 13 14 // NOTE from Ted: to compile from solidity source using the code, make sure 15 // your solc<0.8.0, as geth 1.9.21 does not support the JSON output from 16 // solc>=0.8.0: 17 // See: 18 // - https://github.com/ethereum/go-ethereum/issues/22041 19 // - https://github.com/ethereum/go-ethereum/pull/22092 20 21 package chain 22 23 import ( 24 "crypto/rand" 25 "encoding/json" 26 "fmt" 27 "math/big" 28 "strings" 29 "testing" 30 31 "github.com/ethereum/go-ethereum/accounts/abi" 32 "github.com/ethereum/go-ethereum/common" 33 "github.com/ethereum/go-ethereum/crypto" 34 "github.com/ethereum/go-ethereum/log" 35 "gitlab.com/flarenetwork/coreth/accounts/keystore" 36 "gitlab.com/flarenetwork/coreth/consensus/dummy" 37 "gitlab.com/flarenetwork/coreth/core" 38 "gitlab.com/flarenetwork/coreth/core/rawdb" 39 "gitlab.com/flarenetwork/coreth/core/types" 40 "gitlab.com/flarenetwork/coreth/core/vm" 41 "gitlab.com/flarenetwork/coreth/eth" 42 "gitlab.com/flarenetwork/coreth/eth/ethconfig" 43 "gitlab.com/flarenetwork/coreth/node" 44 ) 45 46 // TestMulticoin tests multicoin low-level state management and regular 47 // transaction/smart contract transfer. 48 func TestMulticoin(t *testing.T) { 49 // configure the chain 50 config := ethconfig.NewDefaultConfig() 51 52 // configure the genesis block 53 genesisJSON := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}, "0100000000000000000000000000000000000000": {"code": "0x73000000000000000000000000000000000000000030146080604052600436106100405760003560e01c80631e01043914610045578063b6510bb314610087575b600080fd5b6100716004803603602081101561005b57600080fd5b81019080803590602001909291905050506100f6565b6040518082815260200191505060405180910390f35b81801561009357600080fd5b506100f4600480360360808110156100aa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050610119565b005b60003073ffffffffffffffffffffffffffffffffffffffff168290cd9050919050565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8acf95505050505050158015610165573d6000803e3d6000fd5b505050505056fea26469706673582212204ca02a58b31e59814fcb487b2bdc205149e01e9f695f02f5e73ae40c4f027c1e64736f6c634300060a0033", "balance": "0x0", "mcbalance": {}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}` 54 mcAbiJSON := `[{"inputs":[{"internalType":"uint256","name":"coinid","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"coinid","type":"uint256"},{"internalType":"uint256","name":"amount2","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"}]` 55 genesisKey := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1" 56 57 bobKey, _ := keystore.NewKey(rand.Reader) 58 genesisBlock := new(core.Genesis) 59 if err := json.Unmarshal([]byte(genesisJSON), genesisBlock); err != nil { 60 t.Fatal(err) 61 } 62 hk, _ := crypto.HexToECDSA(genesisKey[2:]) 63 genKey := keystore.NewKeyFromECDSA(hk) 64 65 config.Genesis = genesisBlock 66 67 // NOTE: use precompiled `mc_test.sol` for portability, do not remove the 68 // following code (for debug purpose) 69 // 70 //// compile the smart contract 71 //gopath := os.Getenv("GOPATH") 72 //if gopath == "" { 73 // gopath = build.Default.GOPATH 74 //} 75 //counterSrc, err := filepath.Abs(gopath + "/src/github.com/ava-labs/coreth/examples/multicoin/mc_test.sol") 76 //if err != nil { 77 // t.Fatal(err) 78 // } 79 //contracts, err := compiler.CompileSolidity("", counterSrc) 80 //if err != nil { 81 // t.Fatal(err) 82 // } 83 //contract, _ := contracts[fmt.Sprintf("%s:%s", counterSrc, "MCTest")] 84 // abiStr, err := json.Marshal(contract.Info.AbiDefinition) 85 // contractAbi, err := abi.JSON(strings.NewReader(string(abiStr))) 86 // if err != nil { 87 // t.Fatal(err) 88 // } 89 // code := common.Hex2Bytes(contract.Code[2:]) 90 91 // see `mc_test.sol` 92 contract := "608060405234801561001057600080fd5b50610426806100206000396000f3fe60806040526004361061002d5760003560e01c8063a41fe49f14610039578063ba7b37d41461008857610034565b3661003457005b600080fd5b34801561004557600080fd5b506100866004803603606081101561005c57600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506100c3565b005b34801561009457600080fd5b506100c1600480360360208110156100ab57600080fd5b810190808035906020019092919050505061025a565b005b600073010000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1633858585604051602401808573ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018381526020018281526020019450505050506040516020818303038152906040527fb6510bb3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b602083106101df57805182526020820191506020810190506020830392506101bc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610241576040519150601f19603f3d011682016040523d82523d6000602084013e610246565b606091505b505090508061025457600080fd5b50505050565b60008073010000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1683604051602401808281526020019150506040516020818303038152906040527f1e010439000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b602083106103495780518252602082019150602081019050602083039250610326565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146103ab576040519150601f19603f3d011682016040523d82523d6000602084013e6103b0565b606091505b5091509150816103bf57600080fd5b8080602001905160208110156103d457600080fd5b810190808051906020019092919050505060008190555050505056fea26469706673582212207931f8bf71bbaeaffac554cafb419604155328b1466fae52488964ccba082f5464736f6c63430007060033" 93 contractAbi, err := abi.JSON(strings.NewReader(`[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"coinid","type":"uint256"}],"name":"updateBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"coinid","type":"uint256"},{"internalType":"uint256","name":"amount2","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]`)) 94 if err != nil { 95 t.Fatal(err) 96 } 97 code := common.Hex2Bytes(contract) 98 99 var ( 100 chain *ETHChain 101 ) 102 chain, err = NewETHChain( 103 &config, 104 &node.Config{}, 105 rawdb.NewMemoryDatabase(), 106 eth.DefaultSettings, 107 new(dummy.ConsensusCallbacks), 108 common.Hash{}, 109 ) 110 if err != nil { 111 t.Fatal(err) 112 } 113 114 newTxPoolHeadChan := make(chan core.NewTxPoolHeadEvent, 1) 115 log.Info(chain.GetGenesisBlock().Hash().Hex()) 116 117 mcAbi, err := abi.JSON(strings.NewReader(mcAbiJSON)) 118 if err != nil { 119 t.Fatal(err) 120 } 121 122 // start the chain 123 chain.GetTxPool().SubscribeNewHeadEvent(newTxPoolHeadChan) 124 txSubmitCh := chain.GetTxSubmitCh() 125 chain.Start() 126 127 nonce := uint64(0) 128 tx := types.NewContractCreation(nonce, big.NewInt(0), uint64(gasLimit), gasPrice, code) 129 signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) 130 if err != nil { 131 t.Fatal(err) 132 } 133 for _, err := range chain.AddRemoteTxs([]*types.Transaction{signedTx}) { 134 if err != nil { 135 t.Fatal(err) 136 } 137 } 138 <-txSubmitCh 139 nonce++ 140 block, err := chain.GenerateBlock() 141 if err != nil { 142 t.Fatal(err) 143 } 144 insertAndAccept(t, chain, block) 145 146 <-newTxPoolHeadChan 147 log.Info("Generated block with new counter contract creation", "blkNumber", block.NumberU64()) 148 149 if txs := block.Transactions(); len(txs) != 1 { 150 t.Fatalf("Expected new block to contain 1 transaction, but found %d", len(txs)) 151 } 152 receipts := chain.GetReceiptsByHash(block.Hash()) 153 if len(receipts) != 1 { 154 t.Fatalf("Expected length of receipts to be 1, but found %d", len(receipts)) 155 } 156 contractAddr := receipts[0].ContractAddress 157 158 // give Bob some initial balance 159 tx = types.NewTransaction(nonce, bobKey.Address, big.NewInt(300000000000000000), uint64(gasLimit), gasPrice, nil) 160 signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey) 161 if err != nil { 162 t.Fatal(err) 163 } 164 chain.AddRemoteTxs([]*types.Transaction{signedTx}) 165 nonce++ 166 <-txSubmitCh 167 block, err = chain.GenerateBlock() 168 if err != nil { 169 t.Fatal(err) 170 } 171 insertAndAccept(t, chain, block) 172 173 // Await block generation 174 <-newTxPoolHeadChan 175 if txs := block.Transactions(); len(txs) != 1 { 176 t.Fatalf("Expected new block to contain 1 transaction, but found %d", len(txs)) 177 } 178 179 bobTransferInput, err := mcAbi.Pack("transfer", bobKey.Address, big.NewInt(0), big.NewInt(0), big.NewInt(100000000000000000)) 180 if err != nil { 181 t.Fatal(err) 182 } 183 contractTransferInput, err := mcAbi.Pack("transfer", contractAddr, big.NewInt(0), big.NewInt(0), big.NewInt(100000000000000000)) 184 if err != nil { 185 t.Fatal(err) 186 } 187 188 // send 5 * 100000000000000000 to Bob 189 // send 5 * 100000000000000000 to the contract 190 for i := 0; i < 5; i++ { 191 // transfer some coin0 balance to Bob 192 tx1 := types.NewTransaction(nonce, vm.BuiltinAddr, big.NewInt(0), uint64(gasLimit), gasPrice, bobTransferInput) 193 signedTx1, err := types.SignTx(tx1, types.NewEIP155Signer(chainID), genKey.PrivateKey) 194 if err != nil { 195 t.Fatal(err) 196 } 197 nonce++ 198 199 // transfer some coin0 balance to the contract 200 tx2 := types.NewTransaction(nonce, vm.BuiltinAddr, big.NewInt(0), uint64(gasLimit), gasPrice, contractTransferInput) 201 signedTx2, err := types.SignTx(tx2, types.NewEIP155Signer(chainID), genKey.PrivateKey) 202 if err != nil { 203 t.Fatal(err) 204 } 205 nonce++ 206 207 for _, err := range chain.AddRemoteTxs([]*types.Transaction{signedTx1, signedTx2}) { 208 if err != nil { 209 t.Fatal(err) 210 } 211 } 212 213 <-txSubmitCh 214 block, err := chain.GenerateBlock() 215 if err != nil { 216 t.Fatal(err) 217 } 218 insertAndAccept(t, chain, block) 219 220 <-newTxPoolHeadChan 221 if txs := block.Transactions(); len(txs) != 2 { 222 t.Fatalf("Expected block to contain 2 transactions, but found %d", len(txs)) 223 } 224 } 225 226 // test contract methods 227 // withdraw 10000000000000000 from contract to Bob 228 input, err := contractAbi.Pack("withdraw", big.NewInt(0), big.NewInt(0), big.NewInt(10000000000000000)) 229 if err != nil { 230 t.Fatal(err) 231 } 232 withdrawTx := types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, input) 233 signedWithdrawTx, err := types.SignTx(withdrawTx, types.NewEIP155Signer(chainID), genKey.PrivateKey) 234 if err != nil { 235 t.Fatal(err) 236 } 237 nonce++ 238 239 input, err = contractAbi.Pack("updateBalance", big.NewInt(0)) 240 if err != nil { 241 t.Fatal(err) 242 } 243 updateBalanceTx := types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, input) 244 signedUpdateBalanceTx, err := types.SignTx(updateBalanceTx, types.NewEIP155Signer(chainID), genKey.PrivateKey) 245 if err != nil { 246 t.Fatal(err) 247 } 248 chain.AddRemoteTxs([]*types.Transaction{signedWithdrawTx, signedUpdateBalanceTx}) 249 250 <-txSubmitCh 251 block, err = chain.GenerateBlock() 252 if err != nil { 253 t.Fatal(err) 254 } 255 insertAndAccept(t, chain, block) 256 257 <-newTxPoolHeadChan 258 259 if txs := block.Transactions(); len(txs) != 2 { 260 t.Fatalf("Expected new block to contain 2 transaction, but found %d", len(txs)) 261 } 262 263 coin0 := common.HexToHash("0x0") 264 state, err := chain.CurrentState() 265 if err != nil { 266 t.Fatal(err) 267 } 268 269 genMCBalance := state.GetBalanceMultiCoin(genKey.Address, coin0) 270 bobMCBalance := state.GetBalanceMultiCoin(bobKey.Address, coin0) 271 contractMCBalance := state.GetBalanceMultiCoin(contractAddr, coin0) 272 273 log.Info(fmt.Sprintf("genesis balance = %s", state.GetBalance(genKey.Address))) 274 log.Info(fmt.Sprintf("genesis mcbalance(0) = %s", genMCBalance)) 275 log.Info(fmt.Sprintf("bob's balance = %s", state.GetBalance(bobKey.Address))) 276 log.Info(fmt.Sprintf("bob's mcbalance(0) = %s", bobMCBalance)) 277 log.Info(fmt.Sprintf("contract mcbalance(0) = %s", contractMCBalance)) 278 279 if genMCBalance.Cmp(big.NewInt(10000000000000000)) != 0 { 280 t.Fatal("incorrect genesis MC balance") 281 } 282 if bobMCBalance.Cmp(big.NewInt(500000000000000000)) != 0 { 283 t.Fatal("incorrect bob's MC balance") 284 } 285 if contractMCBalance.Cmp(big.NewInt(490000000000000000)) != 0 { 286 t.Fatal("incorrect contract's MC balance") 287 } 288 }