/* * Copyright (c) [2016] [ <ether.camp> ] * This file is part of the ethereumJ library. * * The ethereumJ library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ethereumJ library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>. */ package org.ethereum.jsonrpc; import com.typesafe.config.ConfigFactory; import org.ethereum.config.SystemProperties; import org.ethereum.config.blockchain.FrontierConfig; import org.ethereum.core.CallTransaction; import org.ethereum.core.Transaction; import org.ethereum.datasource.DbSource; import org.ethereum.datasource.inmem.HashMapDB; import org.ethereum.facade.Ethereum; import org.ethereum.facade.EthereumFactory; import org.ethereum.facade.EthereumImpl; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; import java.math.BigInteger; import static java.math.BigInteger.valueOf; import static org.ethereum.crypto.HashUtil.sha3; import static org.junit.Assert.*; /** * Created by Anton Nashatyrev on 19.04.2016. */ public class JsonRpcTest { private static class TestConfig { private final String config = // no need for discovery in that small network "peer.discovery.enabled = false \n" + "peer.listen.port = 0 \n" + // need to have different nodeId's for the peers "peer.privateKey = 6ef8da380c27cea8fdf7448340ea99e8e2268fc2950d79ed47cbf6f85dc977ec \n" + // our private net ID "peer.networkId = 555 \n" + // we have no peers to sync with "sync.enabled = false \n" + // genesis with a lower initial difficulty and some predefined known funded accounts "genesis = genesis-light.json \n" + // two peers need to have separate database dirs "database.dir = sampleDB-1 \n" + "keyvalue.datasource = inmem \n" + // when more than 1 miner exist on the network extraData helps to identify the block creator "mine.extraDataHex = cccccccccccccccccccc \n" + "mine.fullDataSet = false \n" + "mine.cpuMineThreads = 2"; /** * Instead of supplying properties via config file for the peer * we are substituting the corresponding bean which returns required * config for this instance. */ @Bean public SystemProperties systemProperties() { SystemProperties props = new SystemProperties(); props.overrideParams(ConfigFactory.parseString(config.replaceAll("'", "\""))); FrontierConfig config = new FrontierConfig(new FrontierConfig.FrontierConstants() { @Override public BigInteger getMINIMUM_DIFFICULTY() { return BigInteger.ONE; } }); SystemProperties.getDefault().setBlockchainConfig(config); props.setBlockchainConfig(config); return props; } @Bean public TestRunner test() { return new TestRunner(); } } static class TestRunner { @Autowired JsonRpc jsonRpc; @Autowired Ethereum ethereum; // @PostConstruct public void runTests() throws Exception { String cowAcct = jsonRpc.personal_newAccount("cow"); String bal0 = jsonRpc.eth_getBalance(cowAcct); System.out.println("Balance: " + bal0); assertTrue(TypeConverter.StringHexToBigInteger(bal0).compareTo(BigInteger.ZERO) > 0); String pendingTxFilterId = jsonRpc.eth_newPendingTransactionFilter(); Object[] changes = jsonRpc.eth_getFilterChanges(pendingTxFilterId); assertEquals(0, changes.length); JsonRpc.CallArguments ca = new JsonRpc.CallArguments(); ca.from = cowAcct; ca.to = "0x0000000000000000000000000000000000001234"; ca.gas = "0x300000"; ca.gasPrice = "0x10000000000"; ca.value = "0x7777"; ca.data = "0x"; long sGas = TypeConverter.StringHexToBigInteger(jsonRpc.eth_estimateGas(ca)).longValue(); String txHash1 = jsonRpc.eth_sendTransaction(cowAcct, "0x0000000000000000000000000000000000001234", "0x300000", "0x10000000000", "0x7777", "0x", "0x00"); System.out.println("Tx hash: " + txHash1); assertTrue(TypeConverter.StringHexToBigInteger(txHash1).compareTo(BigInteger.ZERO) > 0); for (int i = 0; i < 50 && changes.length == 0; i++) { changes = jsonRpc.eth_getFilterChanges(pendingTxFilterId); Thread.sleep(200); } assertEquals(1, changes.length); changes = jsonRpc.eth_getFilterChanges(pendingTxFilterId); assertEquals(0, changes.length); JsonRpc.BlockResult blockResult = jsonRpc.eth_getBlockByNumber("pending", true); System.out.println(blockResult); assertEquals(txHash1, ((TransactionResultDTO) blockResult.transactions[0]).hash); String hash1 = mineBlock(); JsonRpc.BlockResult blockResult1 = jsonRpc.eth_getBlockByHash(hash1, true); assertEquals(hash1, blockResult1.hash); assertEquals(txHash1, ((TransactionResultDTO) blockResult1.transactions[0]).hash); TransactionReceiptDTO receipt1 = jsonRpc.eth_getTransactionReceipt(txHash1); assertEquals(1, receipt1.blockNumber); assertTrue(receipt1.gasUsed > 0); assertEquals(sGas, receipt1.gasUsed); String bal1 = jsonRpc.eth_getBalance(cowAcct); System.out.println("Balance: " + bal0); assertTrue(TypeConverter.StringHexToBigInteger(bal0).compareTo(TypeConverter.StringHexToBigInteger(bal1)) > 0); JsonRpc.CompilationResult compRes = jsonRpc.eth_compileSolidity( "contract A { " + "uint public num; " + "function set(uint a) {" + " num = a; " + " log1(0x1111, 0x2222);" + "}}"); assertEquals(compRes.info.abiDefinition[0].name, "num"); assertEquals(compRes.info.abiDefinition[1].name, "set"); assertTrue(compRes.code.length() > 10); JsonRpc.CallArguments callArgs = new JsonRpc.CallArguments(); callArgs.from = cowAcct; callArgs.data = compRes.code; callArgs.gasPrice = "0x10000000000"; callArgs.gas = "0x1000000"; String txHash2 = jsonRpc.eth_sendTransaction(callArgs); sGas = TypeConverter.StringHexToBigInteger(jsonRpc.eth_estimateGas(callArgs)).longValue(); String hash2 = mineBlock(); JsonRpc.BlockResult blockResult2 = jsonRpc.eth_getBlockByHash(hash2, true); assertEquals(hash2, blockResult2.hash); assertEquals(txHash2, ((TransactionResultDTO) blockResult2.transactions[0]).hash); TransactionReceiptDTO receipt2 = jsonRpc.eth_getTransactionReceipt(txHash2); assertTrue(receipt2.blockNumber > 1); assertTrue(receipt2.gasUsed > 0); assertEquals(sGas, receipt2.gasUsed); assertTrue(TypeConverter.StringHexToByteArray(receipt2.contractAddress).length == 20); JsonRpc.FilterRequest filterReq = new JsonRpc.FilterRequest(); filterReq.topics = new Object[]{"0x2222"}; filterReq.fromBlock = "latest"; filterReq.toBlock = "latest"; String filterId = jsonRpc.eth_newFilter(filterReq); CallTransaction.Function function = CallTransaction.Function.fromSignature("set", "uint"); Transaction rawTx = ethereum.createTransaction(valueOf(2), valueOf(50_000_000_000L), valueOf(3_000_000), TypeConverter.StringHexToByteArray(receipt2.contractAddress), valueOf(0), function.encode(0x777)); rawTx.sign(sha3("cow".getBytes())); String txHash3 = jsonRpc.eth_sendRawTransaction(TypeConverter.toJsonHex(rawTx.getEncoded())); JsonRpc.CallArguments callArgs2= new JsonRpc.CallArguments(); callArgs2.to = receipt2.contractAddress; callArgs2.data = TypeConverter.toJsonHex(CallTransaction.Function.fromSignature("num").encode()); String ret3 = jsonRpc.eth_call(callArgs2, "pending"); String ret4 = jsonRpc.eth_call(callArgs2, "latest"); String hash3 = mineBlock(); JsonRpc.BlockResult blockResult3 = jsonRpc.eth_getBlockByHash(hash3, true); assertEquals(hash3, blockResult3.hash); assertEquals(txHash3, ((TransactionResultDTO) blockResult3.transactions[0]).hash); TransactionReceiptDTO receipt3 = jsonRpc.eth_getTransactionReceipt(txHash3); assertTrue(receipt3.blockNumber > 2); assertTrue(receipt3.gasUsed > 0); Object[] logs = jsonRpc.eth_getFilterLogs(filterId); assertEquals(1, logs.length); assertEquals("0x0000000000000000000000000000000000000000000000000000000000001111", ((JsonRpc.LogFilterElement)logs[0]).data); assertEquals(0, jsonRpc.eth_getFilterLogs(filterId).length); String ret1 = jsonRpc.eth_call(callArgs2, blockResult2.number); String ret2 = jsonRpc.eth_call(callArgs2, "latest"); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000000", ret1); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000777", ret2); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000777", ret3); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000000", ret4); } String mineBlock() throws InterruptedException { String blockFilterId = jsonRpc.eth_newBlockFilter(); jsonRpc.miner_start(); int cnt = 0; String hash1; while (true) { Object[] blocks = jsonRpc.eth_getFilterChanges(blockFilterId); cnt += blocks.length; if (cnt > 0) { hash1 = (String) blocks[0]; break; } Thread.sleep(100); } jsonRpc.miner_stop(); Thread.sleep(100); Object[] blocks = jsonRpc.eth_getFilterChanges(blockFilterId); cnt += blocks.length; System.out.println(cnt + " blocks mined"); boolean b = jsonRpc.eth_uninstallFilter(blockFilterId); assertTrue(b); return hash1; } } @Test public void complexTest() throws Exception { System.out.println("Starting Ethereum..."); Ethereum ethereum = EthereumFactory.createEthereum(TestConfig.class); System.out.println("Ethereum started"); TestRunner testRunner = ((EthereumImpl) ethereum).getApplicationContext().getBean(TestRunner.class); System.out.println("Starting test..."); testRunner.runTests(); System.out.println("Test complete."); } }