github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/rpc/web3/eth_service_test.go (about) 1 package web3_test 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/hyperledger/burrow/acm/balance" 12 "github.com/hyperledger/burrow/crypto" 13 "github.com/hyperledger/burrow/encoding" 14 "github.com/hyperledger/burrow/encoding/web3hex" 15 "github.com/hyperledger/burrow/execution/evm/abi" 16 "github.com/hyperledger/burrow/integration" 17 "github.com/hyperledger/burrow/keys" 18 "github.com/hyperledger/burrow/logging" 19 "github.com/hyperledger/burrow/project" 20 "github.com/hyperledger/burrow/rpc" 21 "github.com/hyperledger/burrow/rpc/web3" 22 "github.com/hyperledger/burrow/txs" 23 "github.com/hyperledger/burrow/txs/payload" 24 "github.com/stretchr/testify/require" 25 ) 26 27 var d = new(web3hex.Decoder).Must() 28 29 // Check we can force set a decimal ChainID 30 const chainID = "15321" 31 32 func TestWeb3Service(t *testing.T) { 33 ctx := context.Background() 34 genesisAccounts := integration.MakePrivateAccounts("burrow", 1) 35 genesisAccounts = append(genesisAccounts, integration.MakeEthereumAccounts("ethereum", 3)...) 36 genesisDoc := integration.TestGenesisDoc(genesisAccounts, 0) 37 genesisDoc.ChainID = chainID 38 config, _ := integration.NewTestConfig(genesisDoc) 39 logger := logging.NewNoopLogger() 40 kern, err := integration.TestKernel(genesisAccounts[0], genesisAccounts, config) 41 require.NoError(t, err) 42 err = kern.Boot() 43 defer kern.Shutdown(ctx) 44 45 dir, err := ioutil.TempDir(os.TempDir(), "") 46 require.NoError(t, err) 47 defer os.RemoveAll(dir) 48 49 store := keys.NewFilesystemKeyStore(dir, true) 50 for _, acc := range genesisAccounts { 51 err = store.StoreKeyPlain(&keys.Key{ 52 CurveType: acc.PrivateKey().CurveType, 53 Address: acc.GetAddress(), 54 PublicKey: *acc.GetPublicKey(), 55 PrivateKey: acc.PrivateKey(), 56 }) 57 require.NoError(t, err) 58 } 59 60 nodeView, err := kern.GetNodeView() 61 require.NoError(t, err) 62 63 accountState := kern.State 64 eventsState := kern.State 65 validatorState := kern.State 66 eth := web3.NewEthService(accountState, eventsState, kern.Blockchain, validatorState, 67 nodeView, kern.Transactor, store, kern.Logger) 68 69 t.Run("Web3Sha3", func(t *testing.T) { 70 result, err := eth.Web3Sha3(&web3.Web3Sha3Params{"0x68656c6c6f20776f726c64"}) // hello world 71 require.NoError(t, err) 72 // hex encoded 73 require.Equal(t, "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad", result.HashedData) 74 }) 75 76 t.Run("NetListening", func(t *testing.T) { 77 result, err := eth.NetListening() 78 require.NoError(t, err) 79 require.Equal(t, true, result.IsNetListening) 80 }) 81 82 t.Run("NetPeerCount", func(t *testing.T) { 83 result, err := eth.NetPeerCount() 84 require.NoError(t, err) 85 require.Equal(t, "0x0", result.NumConnectedPeers) 86 }) 87 88 t.Run("Version+ID", func(t *testing.T) { 89 t.Run("Web3ClientVersion", func(t *testing.T) { 90 result, err := eth.Web3ClientVersion() 91 require.NoError(t, err) 92 require.Equal(t, project.FullVersion(), result.ClientVersion) 93 }) 94 95 t.Run("NetVersion", func(t *testing.T) { 96 result, err := eth.NetVersion() 97 require.NoError(t, err) 98 require.Equal(t, web3hex.Encoder.BigInt(encoding.GetEthChainID(genesisDoc.GetChainID())), result.ChainID) 99 }) 100 101 t.Run("EthProtocolVersion", func(t *testing.T) { 102 result, err := eth.EthProtocolVersion() 103 require.NoError(t, err) 104 require.NotEmpty(t, result.ProtocolVersion) 105 }) 106 107 t.Run("EthChainId", func(t *testing.T) { 108 result, err := eth.EthChainId() 109 require.NoError(t, err) 110 doc := config.GenesisDoc 111 require.Equal(t, web3hex.Encoder.BigInt(encoding.GetEthChainID(doc.GetChainID())), result.ChainId) 112 }) 113 }) 114 115 t.Run("EthTransactions", func(t *testing.T) { 116 var txHash, contractAddress string 117 118 sender := genesisAccounts[1] 119 receivee := genesisAccounts[2].GetPublicKey().GetAddress() 120 acc, err := kern.State.GetAccount(receivee) 121 require.NoError(t, err) 122 before := acc.GetBalance() 123 124 t.Run("EthSendRawTransaction", func(t *testing.T) { 125 txEnv := txs.Enclose(chainID, &payload.CallTx{ 126 Input: &payload.TxInput{ 127 Address: sender.GetAddress(), 128 Amount: 1, 129 Sequence: 0, 130 }, 131 Address: &receivee, 132 Data: nil, 133 }) 134 txEnv.Encoding = txs.Envelope_RLP 135 err = txEnv.Sign(sender) 136 require.NoError(t, err) 137 138 rawTx, err := txs.EthRawTxFromEnvelope(txEnv) 139 require.NoError(t, err) 140 141 bs, err := rawTx.Marshal() 142 require.NoError(t, err) 143 144 raw := web3hex.Encoder.BytesTrim(bs) 145 146 _, err = eth.EthSendRawTransaction(&web3.EthSendRawTransactionParams{ 147 SignedTransactionData: raw, 148 }) 149 require.NoError(t, err) 150 }) 151 152 t.Run("EthGetBalance", func(t *testing.T) { 153 result, err := eth.EthGetBalance(&web3.EthGetBalanceParams{ 154 Address: web3hex.Encoder.BytesTrim(receivee.Bytes()), 155 BlockNumber: "latest", 156 }) 157 require.NoError(t, err) 158 after := d.BigInt(result.GetBalanceResult) 159 after = balance.WeiToNative(after) 160 require.Equal(t, after.Uint64(), before+1) 161 }) 162 163 t.Run("EthGetTransactionCount", func(t *testing.T) { 164 result, err := eth.EthGetTransactionCount(&web3.EthGetTransactionCountParams{ 165 Address: genesisAccounts[1].GetAddress().String(), 166 }) 167 require.NoError(t, err) 168 require.Equal(t, web3hex.Encoder.Uint64(1), result.NonceOrNull) 169 }) 170 171 // create contract on chain 172 t.Run("EthSendTransaction", func(t *testing.T) { 173 type ret struct { 174 *web3.EthSendTransactionResult 175 error 176 } 177 ch := make(chan ret) 178 numSends := 5 179 for i := 0; i < numSends; i++ { 180 idx := i 181 go func() { 182 tx := &web3.EthSendTransactionParams{ 183 Transaction: web3.Transaction{ 184 From: web3hex.Encoder.BytesTrim(genesisAccounts[3].GetAddress().Bytes()), 185 Gas: web3hex.Encoder.Uint64(uint64(40 + idx)), // make tx unique in mempool 186 Data: web3hex.Encoder.BytesTrim(rpc.Bytecode_HelloWorld), 187 }, 188 } 189 result, err := eth.EthSendTransaction(tx) 190 ch <- ret{result, err} 191 }() 192 } 193 for i := 0; i < numSends; i++ { 194 select { 195 case r := <-ch: 196 require.NoError(t, r.error) 197 require.NotEmpty(t, r.TransactionHash) 198 case <-time.After(2 * time.Second): 199 t.Fatalf("timed out waiting for EthSendTransaction result") 200 } 201 } 202 }) 203 204 t.Run("EthGetTransactionReceipt", func(t *testing.T) { 205 sendResult, err := eth.EthSendTransaction(&web3.EthSendTransactionParams{ 206 Transaction: web3.Transaction{ 207 From: web3hex.Encoder.BytesTrim(genesisAccounts[3].GetAddress().Bytes()), 208 Gas: web3hex.Encoder.Uint64(40), 209 Data: web3hex.Encoder.BytesTrim(rpc.Bytecode_HelloWorld), 210 }, 211 }) 212 require.NoError(t, err) 213 txHash = sendResult.TransactionHash 214 require.NotEmpty(t, txHash, "need tx hash to get tx receipt") 215 receiptResult, err := eth.EthGetTransactionReceipt(&web3.EthGetTransactionReceiptParams{ 216 TransactionHash: txHash, 217 }) 218 require.NoError(t, err) 219 contractAddress = receiptResult.Receipt.ContractAddress 220 require.NotEmpty(t, contractAddress) 221 }) 222 223 t.Run("EthCall", func(t *testing.T) { 224 require.NotEmpty(t, contractAddress, "need contract address to call") 225 226 packed, _, err := abi.EncodeFunctionCall(string(rpc.Abi_HelloWorld), "Hello", logger) 227 require.NoError(t, err) 228 229 result, err := eth.EthCall(&web3.EthCallParams{ 230 Transaction: web3.Transaction{ 231 From: web3hex.Encoder.BytesTrim(genesisAccounts[1].GetAddress().Bytes()), 232 To: contractAddress, 233 Data: web3hex.Encoder.BytesTrim(packed), 234 }, 235 }) 236 require.NoError(t, err) 237 238 value := d.Bytes(result.ReturnValue) 239 vars, err := abi.DecodeFunctionReturn(string(rpc.Abi_HelloWorld), "Hello", value) 240 require.NoError(t, err) 241 require.Len(t, vars, 1) 242 require.Equal(t, "Hello, World", vars[0].Value) 243 }) 244 245 t.Run("EthGetCode", func(t *testing.T) { 246 require.NotEmpty(t, contractAddress, "need contract address get code") 247 result, err := eth.EthGetCode(&web3.EthGetCodeParams{ 248 Address: contractAddress, 249 }) 250 require.NoError(t, err) 251 require.Equal(t, web3hex.Encoder.BytesTrim(rpc.DeployedBytecode_HelloWorld), strings.ToLower(result.Bytes)) 252 }) 253 }) 254 255 t.Run("EthMining", func(t *testing.T) { 256 result, err := eth.EthMining() 257 require.NoError(t, err) 258 require.Equal(t, true, result.Mining) 259 }) 260 261 t.Run("EthAccounts", func(t *testing.T) { 262 result, err := eth.EthAccounts() 263 require.NoError(t, err) 264 require.Len(t, result.Addresses, len(genesisAccounts)-1) 265 for _, acc := range genesisAccounts { 266 if acc.PrivateKey().CurveType == crypto.CurveTypeSecp256k1 { 267 require.Contains(t, result.Addresses, web3hex.Encoder.BytesTrim(acc.GetAddress().Bytes())) 268 } 269 } 270 }) 271 272 t.Run("EthSign", func(t *testing.T) { 273 result, err := eth.EthSign(&web3.EthSignParams{ 274 Address: "0x" + genesisAccounts[1].GetAddress().String(), 275 Bytes: "0xdeadbeaf", 276 }) 277 require.NoError(t, err) 278 require.Equal(t, `0x1ba96f3dd6cbbc27aaaafe9d68a5368653f72a5677e365e2505ad207a5e8741949717cfc1cc107583142bfe54b9ba4840f5ad7cb12b224dd97b2fb6a735b93c57a`, result.Signature) 279 }) 280 281 t.Run("EthGetBlock", func(t *testing.T) { 282 numberResult, err := eth.EthGetBlockByNumber(&web3.EthGetBlockByNumberParams{BlockNumber: web3hex.Encoder.Uint64(1)}) 283 require.NoError(t, err) 284 hashResult, err := eth.EthGetBlockByHash(&web3.EthGetBlockByHashParams{BlockHash: numberResult.GetBlockByNumberResult.Hash}) 285 require.NoError(t, err) 286 require.Equal(t, numberResult.GetBlockByNumberResult, hashResult.GetBlockByHashResult) 287 }) 288 289 }