From 8d35862b457c30267fc21b955ea551b9b5207bd3 Mon Sep 17 00:00:00 2001 From: Dmitrii Shmatko Date: Tue, 13 Aug 2019 16:23:35 +0300 Subject: [PATCH 1/3] pow/ethereumj: fix test cases --- .../pow/StandaloneDepositContractTest.java | 61 +++++++++++++------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java b/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java index 0cacd3f5d..89a374c83 100644 --- a/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java +++ b/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java @@ -1,12 +1,5 @@ package org.ethereum.beacon.pow; -import java.math.BigInteger; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; import org.apache.commons.codec.binary.Hex; import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.ChainStart; @@ -27,8 +20,6 @@ import org.ethereum.beacon.crypto.util.BlsKeyPairGenerator; import org.ethereum.beacon.pow.DepositContract.DepositInfo; import org.ethereum.beacon.schedulers.Schedulers; -import org.ethereum.beacon.ssz.SSZBuilder; -import org.ethereum.beacon.ssz.SSZSerializer; import org.ethereum.config.SystemProperties; import org.ethereum.facade.Ethereum; import org.ethereum.solidity.compiler.CompilationResult.ContractMetadata; @@ -49,6 +40,14 @@ import tech.pegasys.artemis.util.bytes.MutableBytes48; import tech.pegasys.artemis.util.uint.UInt64; +import java.math.BigInteger; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + @Ignore public class StandaloneDepositContractTest { @@ -56,7 +55,8 @@ public class StandaloneDepositContractTest { // GENESIS_ACTIVE_VALIDATOR_COUNT = 16 # 2**14 // SECONDS_PER_DAY = 5 - final int MERKLE_TREE_DEPTH = BeaconChainSpec.DEFAULT_CONSTANTS.getDepositContractTreeDepth().intValue(); + final int MERKLE_TREE_DEPTH = + BeaconChainSpec.DEFAULT_CONSTANTS.getDepositContractTreeDepth().intValue(); final Function HASH_FUNCTION = Hashes::sha256; String depositBin = "740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6101406000601f818352015b600061014051602081106100b757600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e357600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012157600080fd5b60c0519050606051600161014051018060405190131561014057600080fd5b809190121561014e57600080fd5b6020811061015b57600080fd5b600260c052602060c02001555b81516001018083528114156100a4575b50506112f956600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63863a311b600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b61017f6112f90361017f60003961017f6112f9036000f3"; @@ -66,6 +66,7 @@ public class StandaloneDepositContractTest { private BeaconChainSpec createSpec() { return new BeaconChainSpec.Builder() .withDefaultHashFunction() + .withVerifyDepositProof(false) .withBlsVerifyProofOfPossession(false) .withConstants( new SpecConstants() { @@ -297,7 +298,6 @@ public void testVerifyDepositRoot() throws InterruptedException { SolidityContract contract = sb.submitNewContract(contractMetadata); sb.createBlock(); - Ethereum ethereum = new StandaloneEthereum(new SystemProperties(), sb); byte[] latestCalculatedDepositRoot = new byte[32]; EthereumJDepositContract depositContract = @@ -361,6 +361,31 @@ protected synchronized void newDeposits( @Test public void testVerifyProofs() { + BeaconChainSpec specWithVerify = + new BeaconChainSpec.Builder() + .withDefaultHashFunction() + .withVerifyDepositProof(true) + .withBlsVerifyProofOfPossession(true) + .withConstants( + new SpecConstants() { + @Override + public UInt64 getMinGenesisActiveValidatorCount() { + return UInt64.valueOf(16); + } + + @Override + public Time getSecondsPerDay() { + return Time.of(5); + } + + @Override + public Time getMinGenesisTime() { + return Time.of(0); + } + }) + .withDefaultHasher() + .build(); + BeaconChainSpec specWithoutVerify = createSpec(); StandaloneBlockchain sb = new StandaloneBlockchain().withAutoblock(true); ContractMetadata contractMetadata = new ContractMetadata(); contractMetadata.abi = ContractAbi.getContractAbi(); @@ -370,7 +395,6 @@ public void testVerifyProofs() { System.out.println(Hex.encodeHexString((byte[]) depositRoot[0])); BlsKeyPairGenerator generator = BlsKeyPairGenerator.createWithoutSeed(); - BeaconChainSpec spec = createSpec(); List eth1DataList = new ArrayList<>(); for (int i = 0; i < 20; i++) { BLS381.KeyPair keyPair = generator.next(); @@ -386,7 +410,8 @@ public void testVerifyProofs() { // Let signature be the result of bls_sign of the signing_root(deposit_data) with // domain=DOMAIN_DEPOSIT. MessageParameters messageParameters = - MessageParameters.create(spec.signing_root(depositData), SignatureDomains.DEPOSIT); + MessageParameters.create( + specWithVerify.signing_root(depositData), SignatureDomains.DEPOSIT); BLS381.Signature signature = BLS381.sign(messageParameters, keyPair); SolidityCallResult result = @@ -430,7 +455,7 @@ public void testVerifyProofs() { Schedulers.createDefault(), HASH_FUNCTION, MERKLE_TREE_DEPTH, - spec); + specWithoutVerify); depositContract.setDistanceFromHead(3); ChainStart chainStart = @@ -445,8 +470,8 @@ public void testVerifyProofs() { // logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and // computing updated proofs against the latest_eth1_data.deposit_root as needed. See // minimal_merkle.py for a sample implementation. - spec.verify_deposit(beaconState, deposit); - spec.process_deposit(beaconState, deposit); + specWithVerify.verify_deposit(beaconState, deposit); + specWithVerify.process_deposit(beaconState, deposit); } depositRoot = contract.callConstFunction("get_hash_tree_root"); @@ -465,8 +490,8 @@ public void testVerifyProofs() { for (DepositInfo depositInfo : depositInfos1) { beaconState.setEth1Data( eth1DataList.get(depositInfo.getEth1Data().getDepositCount().decrement().intValue())); - spec.verify_deposit(beaconState, depositInfo.getDeposit()); - spec.process_deposit(beaconState, depositInfo.getDeposit()); + specWithVerify.verify_deposit(beaconState, depositInfo.getDeposit()); + specWithVerify.process_deposit(beaconState, depositInfo.getDeposit()); } } From 6eb60b3aa86c9416e872455739e24a3d5512be88 Mon Sep 17 00:00:00 2001 From: Dmitrii Shmatko Date: Thu, 15 Aug 2019 00:29:26 +0300 Subject: [PATCH 2/3] pow/web3j implementation + pow/ethereumj fixes --- .../org/ethereum/beacon/pow/ContractAbi.java | 16 - .../ethereum/beacon/pow/ContractSource.java | 20 ++ .../org/ethereum/beacon/pow/ContractBin.bin | 1 + .../beacon/pow/EthereumJDepositContract.java | 2 +- .../pow/EthereumJTransactionBuilder.java | 2 +- .../pow/StandaloneDepositContractTest.java | 13 +- pow/web3j/build.gradle | 14 + .../beacon/pow/Web3JDepositContract.java | 312 ++++++++++++++++++ .../beacon/pow/Web3JTransactionBuilder.java | 117 +++++++ .../beacon/pow/Web3JTransactionGateway.java | 42 +++ .../beacon/pow/Web3RequestExecutor.java | 77 +++++ .../beacon/pow/contract/DepositContract.java | 183 ++++++++++ .../ethereum/beacon/pow/util/BloomFilter.java | 70 ++++ .../beacon/pow/AbstractWeb3JTest.java | 124 +++++++ .../ethereum/beacon/pow/BloomFilterTest.java | 28 ++ .../pow/Web3JDepositContractProofTest.java | 159 +++++++++ .../pow/Web3JDepositContractRootTest.java | 116 +++++++ .../beacon/pow/Web3JDepositContractTest.java | 127 +++++++ pow/web3j/src/test/resources/geth/Dockerfile | 23 ++ pow/web3j/src/test/resources/geth/README.md | 14 + .../src/test/resources/geth/genesis.json | 18 + pow/web3j/src/test/resources/geth/geth.sh | 8 + pow/web3j/src/test/resources/log4j2.xml | 16 + settings.gradle | 2 +- versions.gradle | 2 + 25 files changed, 1480 insertions(+), 26 deletions(-) delete mode 100644 pow/core/src/main/java/org/ethereum/beacon/pow/ContractAbi.java create mode 100644 pow/core/src/main/java/org/ethereum/beacon/pow/ContractSource.java create mode 100644 pow/core/src/main/resources/org/ethereum/beacon/pow/ContractBin.bin create mode 100644 pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JDepositContract.java create mode 100644 pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionBuilder.java create mode 100644 pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionGateway.java create mode 100644 pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3RequestExecutor.java create mode 100644 pow/web3j/src/main/java/org/ethereum/beacon/pow/contract/DepositContract.java create mode 100644 pow/web3j/src/main/java/org/ethereum/beacon/pow/util/BloomFilter.java create mode 100644 pow/web3j/src/test/java/org/ethereum/beacon/pow/AbstractWeb3JTest.java create mode 100644 pow/web3j/src/test/java/org/ethereum/beacon/pow/BloomFilterTest.java create mode 100644 pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractProofTest.java create mode 100644 pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractRootTest.java create mode 100644 pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractTest.java create mode 100644 pow/web3j/src/test/resources/geth/Dockerfile create mode 100644 pow/web3j/src/test/resources/geth/README.md create mode 100644 pow/web3j/src/test/resources/geth/genesis.json create mode 100755 pow/web3j/src/test/resources/geth/geth.sh create mode 100644 pow/web3j/src/test/resources/log4j2.xml diff --git a/pow/core/src/main/java/org/ethereum/beacon/pow/ContractAbi.java b/pow/core/src/main/java/org/ethereum/beacon/pow/ContractAbi.java deleted file mode 100644 index d660d168b..000000000 --- a/pow/core/src/main/java/org/ethereum/beacon/pow/ContractAbi.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.ethereum.beacon.pow; - -import java.util.Scanner; - -public class ContractAbi { - - private ContractAbi() {} - - public static String getContractAbi() { - // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks - return new Scanner( - ContractAbi.class.getResourceAsStream("ContractAbi.json"), "UTF-8") - .useDelimiter("\\A") - .next(); - } -} diff --git a/pow/core/src/main/java/org/ethereum/beacon/pow/ContractSource.java b/pow/core/src/main/java/org/ethereum/beacon/pow/ContractSource.java new file mode 100644 index 000000000..9e02dee6f --- /dev/null +++ b/pow/core/src/main/java/org/ethereum/beacon/pow/ContractSource.java @@ -0,0 +1,20 @@ +package org.ethereum.beacon.pow; + +import java.util.Scanner; + +public class ContractSource { + + private ContractSource() {} + + public static String getContractAbi() { + // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks + return new Scanner(ContractSource.class.getResourceAsStream("ContractAbi.json"), "UTF-8") + .useDelimiter("\\A") + .next(); + } + + public static String getContractBin() { + // one-liner file + return new Scanner(ContractSource.class.getResourceAsStream("ContractBin.bin"), "UTF-8").next(); + } +} diff --git a/pow/core/src/main/resources/org/ethereum/beacon/pow/ContractBin.bin b/pow/core/src/main/resources/org/ethereum/beacon/pow/ContractBin.bin new file mode 100644 index 000000000..73900c2e9 --- /dev/null +++ b/pow/core/src/main/resources/org/ethereum/beacon/pow/ContractBin.bin @@ -0,0 +1 @@ +740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6101406000601f818352015b600061014051602081106100b757600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e357600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012157600080fd5b60c0519050606051600161014051018060405190131561014057600080fd5b809190121561014e57600080fd5b6020811061015b57600080fd5b600260c052602060c02001555b81516001018083528114156100a4575b50506112f956600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63863a311b600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b61017f6112f90361017f60003961017f6112f9036000f3 \ No newline at end of file diff --git a/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJDepositContract.java b/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJDepositContract.java index 60bd7704d..be2a64e8b 100644 --- a/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJDepositContract.java +++ b/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJDepositContract.java @@ -65,7 +65,7 @@ public EthereumJDepositContract( contractDeployAddressHash = Hash32.wrap(Bytes32.wrap(HashUtil.sha3(this.contractDeployAddress.extractArray()))); this.contractAddressBloom = Bloom.create(contractDeployAddressHash.extractArray()); - this.contract = new Contract(ContractAbi.getContractAbi()); + this.contract = new Contract(ContractSource.getContractAbi()); this.contractDeployBlock = contractDeployBlock; processedUpToBlock = contractDeployBlock; blockExecutor = new LatestExecutor<>(this.schedulers.blocking(), this::processBlocksUpTo); diff --git a/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java b/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java index 103a0b24e..3d30d38df 100644 --- a/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java +++ b/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java @@ -27,7 +27,7 @@ public class EthereumJTransactionBuilder implements TransactionBuilder { public EthereumJTransactionBuilder(Ethereum ethereum, String contractDeployAddress) { this.ethereum = ethereum; this.contractDeployAddress = Address.fromHexString(contractDeployAddress); - this.contract = new CallTransaction.Contract(ContractAbi.getContractAbi()); + this.contract = new CallTransaction.Contract(ContractSource.getContractAbi()); this.gasPriceTracker = new RecommendedGasPriceTracker(); ethereum.addListener(gasPriceTracker); } diff --git a/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java b/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java index 89a374c83..dbea441b6 100644 --- a/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java +++ b/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java @@ -58,8 +58,7 @@ public class StandaloneDepositContractTest { final int MERKLE_TREE_DEPTH = BeaconChainSpec.DEFAULT_CONSTANTS.getDepositContractTreeDepth().intValue(); final Function HASH_FUNCTION = Hashes::sha256; - String depositBin = - "740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6101406000601f818352015b600061014051602081106100b757600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e357600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012157600080fd5b60c0519050606051600161014051018060405190131561014057600080fd5b809190121561014e57600080fd5b6020811061015b57600080fd5b600260c052602060c02001555b81516001018083528114156100a4575b50506112f956600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63863a311b600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b61017f6112f90361017f60003961017f6112f9036000f3"; + final String depositBin = ContractSource.getContractBin(); BigInteger gweiAmount = BigInteger.valueOf(32L * 1_000_000_000L); BigInteger depositAmount = gweiAmount.multiply(BigInteger.valueOf(1_000_000_000L)); @@ -93,7 +92,7 @@ public Time getMinGenesisTime() { public void test1() { StandaloneBlockchain sb = new StandaloneBlockchain().withAutoblock(true); ContractMetadata contractMetadata = new ContractMetadata(); - contractMetadata.abi = ContractAbi.getContractAbi(); + contractMetadata.abi = ContractSource.getContractAbi(); contractMetadata.bin = depositBin; SolidityContract contract = sb.submitNewContract(contractMetadata); Object[] depositRoot = contract.callConstFunction("get_hash_tree_root"); @@ -177,7 +176,7 @@ public void test1() { public void testOnline() { StandaloneBlockchain sb = new StandaloneBlockchain(); ContractMetadata contractMetadata = new ContractMetadata(); - contractMetadata.abi = ContractAbi.getContractAbi(); + contractMetadata.abi = ContractSource.getContractAbi(); contractMetadata.bin = depositBin; SolidityContract contract = sb.submitNewContract(contractMetadata); sb.createBlock(); @@ -293,7 +292,7 @@ public void testOnline() { public void testVerifyDepositRoot() throws InterruptedException { StandaloneBlockchain sb = new StandaloneBlockchain(); ContractMetadata contractMetadata = new ContractMetadata(); - contractMetadata.abi = ContractAbi.getContractAbi(); + contractMetadata.abi = ContractSource.getContractAbi(); contractMetadata.bin = depositBin; SolidityContract contract = sb.submitNewContract(contractMetadata); sb.createBlock(); @@ -388,7 +387,7 @@ public Time getMinGenesisTime() { BeaconChainSpec specWithoutVerify = createSpec(); StandaloneBlockchain sb = new StandaloneBlockchain().withAutoblock(true); ContractMetadata contractMetadata = new ContractMetadata(); - contractMetadata.abi = ContractAbi.getContractAbi(); + contractMetadata.abi = ContractSource.getContractAbi(); contractMetadata.bin = depositBin; SolidityContract contract = sb.submitNewContract(contractMetadata); Object[] depositRoot = contract.callConstFunction("get_hash_tree_root"); @@ -507,7 +506,7 @@ public void testVyperAbi() { contractMetadata.bin = abiTestBin.replace("0x", ""); SolidityContract contract = sb.submitNewContract(contractMetadata); ((SolidityContractImpl) contract) - .addRelatedContract(ContractAbi.getContractAbi()); // TODO ethJ bug workaround + .addRelatedContract(ContractSource.getContractAbi()); // TODO ethJ bug workaround byte[] bytes = new byte[64]; Arrays.fill(bytes, (byte) 0x33); diff --git a/pow/web3j/build.gradle b/pow/web3j/build.gradle index e69de29bb..968590096 100644 --- a/pow/web3j/build.gradle +++ b/pow/web3j/build.gradle @@ -0,0 +1,14 @@ +dependencies { + implementation project(':pow:core') + implementation project(':pow:validator') + implementation project(':types') + implementation project(':consensus') + implementation project(':util') + implementation project(':crypto') + implementation project(':core') + + implementation 'org.apache.logging.log4j:log4j-core' + implementation 'org.slf4j:slf4j-simple' + implementation 'io.projectreactor:reactor-core' + implementation 'org.web3j:core' +} diff --git a/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JDepositContract.java b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JDepositContract.java new file mode 100644 index 000000000..b3cbd90ec --- /dev/null +++ b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JDepositContract.java @@ -0,0 +1,312 @@ +package org.ethereum.beacon.pow; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.ethereum.beacon.consensus.BeaconChainSpec; +import org.ethereum.beacon.pow.contract.DepositContract; +import org.ethereum.beacon.pow.util.BloomFilter; +import org.ethereum.beacon.schedulers.LatestExecutor; +import org.ethereum.beacon.schedulers.Schedulers; +import org.javatuples.Pair; +import org.javatuples.Triplet; +import org.web3j.crypto.Credentials; +import org.web3j.crypto.ECKeyPair; +import org.web3j.crypto.Hash; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameter; +import org.web3j.protocol.core.methods.response.EthBlock; +import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tx.gas.DefaultGasProvider; +import org.web3j.utils.Numeric; +import tech.pegasys.artemis.ethereum.core.Address; +import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.Bytes8; +import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.uint.UInt64; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class Web3JDepositContract extends AbstractDepositContract { + private static final Logger logger = LogManager.getLogger(Web3JDepositContract.class); + + private final LatestExecutor blockExecutor; + private final Web3j web3j; + private final Web3RequestExecutor web3RequestExecutor; + private final org.ethereum.beacon.pow.contract.DepositContract depositContract; + private final Address contractDeployAddress; + private final Hash32 contractDeployAddressHash; + private final long contractDeployBlock; + private final BloomFilter contractAddressBloom; + private volatile long processedUpToBlock; + private boolean chainStartComplete; + + public Web3JDepositContract( + Web3j web3j, + String contractDeployAddress, + long contractDeployBlock, + Schedulers schedulers, + Function hashFunction, + int merkleTreeDepth, + BeaconChainSpec spec) { + super(schedulers, hashFunction, merkleTreeDepth, spec); + this.web3j = web3j; + + this.contractDeployAddress = Address.fromHexString(contractDeployAddress); + contractDeployAddressHash = + Hash32.wrap(Bytes32.wrap(Hash.sha3(this.contractDeployAddress.extractArray()))); + this.contractAddressBloom = BloomFilter.create(contractDeployAddressHash.extractArray()); + this.contractDeployBlock = contractDeployBlock; + this.depositContract = + org.ethereum.beacon.pow.contract.DepositContract.load( + contractDeployAddress, + web3j, + Credentials.create(ECKeyPair.create(BigInteger.ONE)), + new DefaultGasProvider()); + + processedUpToBlock = contractDeployBlock; + blockExecutor = new LatestExecutor<>(this.schedulers.blocking(), this::processBlocksUpTo); + this.web3RequestExecutor = new Web3RequestExecutor(web3j); + } + + @Override + protected void chainStartSubscribed() { + web3RequestExecutor.executeOnSyncDone( + () -> { + processConfirmedBlocks(); + onEthereumUpdated(); + }); + web3j + .blockFlowable(false) + .doOnNext( + block -> { + onEthereumUpdated(); + }) + .subscribe(); + } + + @Override + protected void chainStartDone() { + chainStartComplete = true; + } + + private void onEthereumUpdated() { + processConfirmedBlocks(); + } + + long getBestConfirmedBlock() { + return web3j.ethBlockNumber().sendAsync().join().getBlockNumber().longValue() + - getDistanceFromHead(); + } + + void processConfirmedBlocks() { + long bestConfirmedBlock = getBestConfirmedBlock(); + blockExecutor.newEvent(bestConfirmedBlock); + } + + void processBlocksUpTo(long bestConfirmedBlock) { + for (long number = processedUpToBlock; number <= bestConfirmedBlock; number++) { + EthBlock block = + web3j + .ethGetBlockByNumber(DefaultBlockParameter.valueOf(BigInteger.valueOf(number)), false) + .sendAsync() + .join(); + onConfirmedBlock(block.getBlock()); + processedUpToBlock = number + 1; + } + } + + private Optional getReceiptFor(EthBlock.TransactionResult txResult) { + CompletableFuture future; + if (txResult instanceof EthBlock.TransactionHash) { + future = + web3j.ethGetTransactionReceipt(((EthBlock.TransactionHash) txResult).get()).sendAsync(); + } else if (txResult instanceof EthBlock.TransactionObject) { + future = + web3j + .ethGetTransactionReceipt(((EthBlock.TransactionObject) txResult).get().getHash()) + .sendAsync(); + } else { + throw new RuntimeException("txResult type not supported for txResult: " + txResult); + } + + return future.thenApply(EthGetTransactionReceipt::getTransactionReceipt).join(); + } + + private List getBlockTransactionReceipts(EthBlock.Block block) { + return block.getTransactions().stream() + .map(this::getReceiptFor) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } + + private synchronized void onConfirmedBlock(EthBlock.Block block) { + List depositEventDataList = getDepositEvents(block); + if (!depositEventDataList.isEmpty()) { + newDeposits( + depositEventDataList, + Numeric.hexStringToByteArray(block.getHash()), + block.getTimestamp().longValue()); + } + } + + private DepositEventData createDepositEventData(DepositContract.DepositEventEventResponse event) { + return new DepositEventData( + event.pubkey, event.withdrawal_credentials, event.amount, event.signature, event.index); + } + + private List getDepositEvents(EthBlock.Block block) { + if (!new BloomFilter(Numeric.hexStringToByteArray(block.getLogsBloom())) + .matches(contractAddressBloom)) { + return Collections.emptyList(); + } + + List ret = new ArrayList<>(); + List receipts = getBlockTransactionReceipts(block); + for (TransactionReceipt receipt : receipts) { + List responses = + depositContract.getDepositEventEvents(receipt); + List depositEvents = + responses.stream().map(this::createDepositEventData).collect(Collectors.toList()); + ret.addAll(depositEvents); + } + + return ret; + } + + @Override + protected boolean hasDepositRootImpl(byte[] blockHash, byte[] depositRoot) { + EthBlock.Block block = + web3j + .ethGetBlockByHash(Numeric.toHexString(blockHash), false) + .sendAsync() + .join() + .getBlock(); + if (block == null || block.getNumber().longValue() > getBestConfirmedBlock()) { + return false; + } + + return getDepositEvents(block).stream() + .anyMatch(depositEvent -> Arrays.equals(depositEvent.pubkey, depositRoot)); + } + + @Override + protected synchronized Optional> + getLatestBlockHashDepositRoot() { + long bestBlock = getBestConfirmedBlock(); + for (long blockNum = bestBlock; blockNum >= contractDeployBlock; blockNum--) { + EthBlock.Block block = + web3j + .ethGetBlockByNumber( + DefaultBlockParameter.valueOf(BigInteger.valueOf(blockNum)), false) + .sendAsync() + .join() + .getBlock(); + List contractEvents = getDepositEvents(block); + Collections.reverse(contractEvents); + for (DepositEventData eventData : contractEvents) { + return Optional.of( + Triplet.with( + getDepositRoot(eventData.index).extractArray(), + UInt64.fromBytesLittleEndian(Bytes8.wrap(eventData.index)).increment().intValue(), + Numeric.hexStringToByteArray(block.getHash()))); + } + } + + return Optional.empty(); + } + + @Override + protected List>> peekDepositsImpl( + int count, byte[] startBlockHash, byte[] endBlockHash) { + List>> ret = new ArrayList<>(); + + CompletableFuture startBlockFut = + web3j.ethGetBlockByHash(Numeric.toHexString(startBlockHash), false).sendAsync(); + CompletableFuture endBlockFut = + web3j.ethGetBlockByHash(Numeric.toHexString(endBlockHash), false).sendAsync(); + CompletableFuture.allOf(startBlockFut, endBlockFut).join(); + + Iterator>> iterator = + iterateDepositEvents(startBlockFut.join().getBlock(), endBlockFut.join().getBlock()); + boolean started = false; + while (iterator.hasNext()) { + if (Arrays.equals( + startBlockHash, Numeric.hexStringToByteArray(iterator.next().getValue0().getHash()))) { + started = true; + break; + } + } + + if (!started) { + return ret; + } + + while (iterator.hasNext() && count > 0) { + Pair> event = iterator.next(); + ret.add( + Pair.with(Numeric.hexStringToByteArray(event.getValue0().getHash()), event.getValue1())); + count--; + if (Arrays.equals(endBlockHash, Numeric.hexStringToByteArray(event.getValue0().getHash()))) { + break; + } + } + + return ret; + } + + private Iterator>> iterateDepositEvents( + EthBlock.Block fromInclusive, EthBlock.Block tillInclusive) { + return new Iterator>>() { + Iterator> iterator = Collections.emptyIterator(); + EthBlock.Block curBlock; + + @Override + public boolean hasNext() { + while (!iterator.hasNext()) { + if (curBlock == null) { + curBlock = fromInclusive; + } else { + if (curBlock.getNumber().longValue() >= tillInclusive.getNumber().longValue()) { + return false; + } + if (getBestConfirmedBlock() <= curBlock.getNumber().longValue()) { + return false; + } + curBlock = + web3j + .ethGetBlockByNumber( + DefaultBlockParameter.valueOf(curBlock.getNumber().add(BigInteger.ONE)), + false) + .sendAsync() + .join() + .getBlock(); + } + List cur = getDepositEvents(curBlock); + if (!cur.isEmpty()) { + List> iteratorList = new ArrayList<>(); + iteratorList.add(cur); + iterator = iteratorList.iterator(); + } + } + return true; + } + + @Override + public Pair> next() { + return Pair.with(curBlock, iterator.next()); + } + }; + } +} diff --git a/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionBuilder.java b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionBuilder.java new file mode 100644 index 000000000..0bef0e2a7 --- /dev/null +++ b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionBuilder.java @@ -0,0 +1,117 @@ +package org.ethereum.beacon.pow; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.ethereum.beacon.core.operations.deposit.DepositData; +import org.ethereum.beacon.core.types.Gwei; +import org.ethereum.beacon.pow.validator.TransactionBuilder; +import org.web3j.abi.FunctionEncoder; +import org.web3j.abi.datatypes.Function; +import org.web3j.crypto.Credentials; +import org.web3j.crypto.ECKeyPair; +import org.web3j.crypto.RawTransaction; +import org.web3j.crypto.TransactionEncoder; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameterName; +import org.web3j.protocol.core.methods.response.EthGasPrice; +import org.web3j.protocol.core.methods.response.EthGetTransactionCount; +import org.web3j.rlp.RlpDecoder; +import org.web3j.rlp.RlpEncoder; +import org.web3j.rlp.RlpList; +import org.web3j.rlp.RlpString; +import org.web3j.utils.Convert; +import tech.pegasys.artemis.ethereum.core.Address; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; + +import static org.ethereum.beacon.pow.contract.DepositContract.FUNC_DEPOSIT; + +public class Web3JTransactionBuilder implements TransactionBuilder { + private static final Logger logger = LogManager.getLogger(Web3JTransactionBuilder.class); + private final Web3j web3j; + private final Address contractDeployAddress; + private final Web3RequestExecutor web3RequestExecutor; + + public Web3JTransactionBuilder(Web3j web3j, String contractDeployAddress) { + this.web3j = web3j; + this.contractDeployAddress = Address.fromHexString(contractDeployAddress); + this.web3RequestExecutor = new Web3RequestExecutor(web3j); + } + + @Override + public CompletableFuture createTransaction( + String fromAddress, DepositData depositData, Gwei amount) { + CompletableFuture result = new CompletableFuture<>(); + web3RequestExecutor.executeOnSyncDone( + () -> { + CompletableFuture txCountFut = + web3j + .ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST) + .sendAsync(); + CompletableFuture gasPriceFut = web3j.ethGasPrice().sendAsync(); + CompletableFuture.allOf(txCountFut, gasPriceFut) + .thenAccept( + aVoid -> { + BigInteger nonce = txCountFut.join().getTransactionCount(); + BigInteger value = + Convert.toWei(amount.longValue() + "", Convert.Unit.GWEI).toBigInteger(); + BigInteger gasLimit = BigInteger.valueOf(2_000_000); + final Function function = + new Function( + FUNC_DEPOSIT, + Arrays.asList( + new org.web3j.abi.datatypes.DynamicBytes( + depositData.getPubKey().extractArray()), + new org.web3j.abi.datatypes.DynamicBytes( + depositData.getWithdrawalCredentials().extractArray()), + new org.web3j.abi.datatypes.DynamicBytes( + depositData.getSignature().extractArray())), + Collections.emptyList()); + String encodedFunction = FunctionEncoder.encode(function); + byte[] rawTransaction = + RlpEncoder.encode( + new RlpList( + RlpString.create(nonce), + RlpString.create(gasPriceFut.join().getGasPrice()), + RlpString.create(gasLimit), + RlpString.create(contractDeployAddress.toString()), + RlpString.create(value), + RlpString.create(encodedFunction))); + result.complete(BytesValue.wrap(rawTransaction)); + }); + }); + + return result; + } + + @Override + public CompletableFuture signTransaction( + BytesValue unsignedTransaction, BytesValue eth1PrivKey) { + CompletableFuture result = new CompletableFuture<>(); + web3RequestExecutor.executeOnSyncDone( + () -> { + RlpList list = RlpDecoder.decode(unsignedTransaction.extractArray()); + ECKeyPair keyPair = ECKeyPair.create(eth1PrivKey.extractArray()); + // by client, so this module provides an opportunity to + // manage private key by 3rd party application + RawTransaction rawTransaction = + RawTransaction.createTransaction( + ((RlpString) list.getValues().get(0)).asPositiveBigInteger(), // nonce + ((RlpString) list.getValues().get(1)).asPositiveBigInteger(), // gas price + ((RlpString) list.getValues().get(2)).asPositiveBigInteger(), // gas limit + ((RlpString) list.getValues().get(3)).asString(), // contract address + ((RlpString) list.getValues().get(4)).asPositiveBigInteger(), // amount + ((RlpString) list.getValues().get(5)).asString() // data + ); + byte[] signedTx = + TransactionEncoder.signMessage(rawTransaction, Credentials.create(keyPair)); + result.complete(BytesValue.wrap(signedTx)); + }); + + return result; + } +} diff --git a/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionGateway.java b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionGateway.java new file mode 100644 index 000000000..4c77e9185 --- /dev/null +++ b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3JTransactionGateway.java @@ -0,0 +1,42 @@ +package org.ethereum.beacon.pow; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.ethereum.beacon.pow.validator.TransactionGateway; +import org.web3j.protocol.Web3j; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import java.util.concurrent.CompletableFuture; + +public class Web3JTransactionGateway implements TransactionGateway { + private static final Logger logger = LogManager.getLogger(Web3JTransactionGateway.class); + private final Web3RequestExecutor web3RequestExecutor; + private final Web3j web3j; + + public Web3JTransactionGateway(Web3j web3j) { + this.web3j = web3j; + this.web3RequestExecutor = new Web3RequestExecutor(web3j); + } + + @Override + public CompletableFuture send(BytesValue signedTransaction) { + CompletableFuture result = new CompletableFuture<>(); + web3RequestExecutor.executeOnSyncDone( + () -> { + web3j + .ethSendRawTransaction(signedTransaction.toString()) + .sendAsync() + .thenAccept( + ethSendTransaction -> { + if (ethSendTransaction == null + || ethSendTransaction.getTransactionHash() == null) { + result.complete(TxStatus.ERROR); + } else { + result.complete(TxStatus.SUCCESS); + } + }); + }); + + return result; + } +} diff --git a/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3RequestExecutor.java b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3RequestExecutor.java new file mode 100644 index 000000000..790099b13 --- /dev/null +++ b/pow/web3j/src/main/java/org/ethereum/beacon/pow/Web3RequestExecutor.java @@ -0,0 +1,77 @@ +package org.ethereum.beacon.pow; + +import io.reactivex.schedulers.Schedulers; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameterName; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +class Web3RequestExecutor { + private final Logger logger = LogManager.getLogger(Web3RequestExecutor.class); + private final Web3j web3j; + + private static final Integer TIMEOUT_MS = 5 * 1000; + private static final Integer REPEAT_INTERVAL_MS = 3 * 1000; + private static final Integer SYNC_THRESHOLD = 1000 * 60 * 3; + + public Web3RequestExecutor(Web3j web3j) { + this.web3j = web3j; + } + + private boolean isReady() { + CompletableFuture notReadySyncing = new CompletableFuture<>(); + CompletableFuture notSyncing = new CompletableFuture<>(); + web3j + .ethSyncing() + .sendAsync() + .thenAccept( + ethSyncing -> { + if (ethSyncing.isSyncing()) { + notReadySyncing.complete(false); + } else { + notSyncing.complete(null); + } + }); + CompletableFuture syncingNotStalled = + notSyncing + .thenComposeAsync( + aVoid -> + web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false).sendAsync()) + .thenApply( + ethBlock -> { + long timestamp = ethBlock.getBlock().getTimestamp().longValueExact() * 1000; + return System.currentTimeMillis() - SYNC_THRESHOLD < timestamp; + }); + + try { + return notReadySyncing + .applyToEither(syncingNotStalled, java.util.function.Function.identity()) + .get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (Exception e) { + logger.debug("Unable to get isReady peer status because of exception", e); + return false; + } + } + + void executeOnSyncDone(Runnable runnable) { + CompletableFuture finished = new CompletableFuture<>(); + Schedulers.single() + .scheduleDirect( + () -> { + while (!finished.isDone()) { + try { + if (isReady()) { + runnable.run(); + finished.complete(true); + } + Thread.sleep(REPEAT_INTERVAL_MS); + } catch (InterruptedException e) { + logger.error("Sync task was interrupted by exception", e); + } + } + }); + } +} diff --git a/pow/web3j/src/main/java/org/ethereum/beacon/pow/contract/DepositContract.java b/pow/web3j/src/main/java/org/ethereum/beacon/pow/contract/DepositContract.java new file mode 100644 index 000000000..0190c8dd1 --- /dev/null +++ b/pow/web3j/src/main/java/org/ethereum/beacon/pow/contract/DepositContract.java @@ -0,0 +1,183 @@ +package org.ethereum.beacon.pow.contract; + +import io.reactivex.Flowable; +import io.reactivex.functions.Function; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.ethereum.beacon.pow.ContractSource; +import org.web3j.abi.EventEncoder; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.DynamicBytes; +import org.web3j.abi.datatypes.Event; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.generated.Bytes32; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameter; +import org.web3j.protocol.core.RemoteCall; +import org.web3j.protocol.core.methods.request.EthFilter; +import org.web3j.protocol.core.methods.response.Log; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tx.Contract; +import org.web3j.tx.TransactionManager; +import org.web3j.tx.gas.ContractGasProvider; + +/** + *

Auto generated code. + *

Do not modify! + *

Please use the web3j command line tools, + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. + * + *

Generated with web3j version 4.3.2-SNAPSHOT. + * + *

Generated with following input: org.web3j.codegen.SolidityFunctionWrapperGenerator.java -b /home/work/projects/beacon-chain-java/pow/core/src/main/resources/org/ethereum/beacon/pow/ContractBin.bin -a /home/work/projects/beacon-chain-java/pow/core/src/main/resources/org/ethereum/beacon/pow/ContractAbi.json -o /home/work/projects/beacon-chain-java/pow/web3j/src/main/java -p org.ethereum.beacon.pow.contract

+ */ +public class DepositContract extends Contract { + private static final String BINARY = ContractSource.getContractBin(); + + public static final String FUNC_GET_HASH_TREE_ROOT = "get_hash_tree_root"; + + public static final String FUNC_GET_DEPOSIT_COUNT = "get_deposit_count"; + + public static final String FUNC_DEPOSIT = "deposit"; + + public static final Event DEPOSITEVENT_EVENT = new Event("DepositEvent", + Arrays.>asList(new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference() {})); + ; + + @Deprecated + protected DepositContract(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + protected DepositContract(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, credentials, contractGasProvider); + } + + @Deprecated + protected DepositContract(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + protected DepositContract(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); + } + + public List getDepositEventEvents(TransactionReceipt transactionReceipt) { + List valueList = extractEventParametersWithLog(DEPOSITEVENT_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + DepositEventEventResponse typedResponse = new DepositEventEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.pubkey = (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.withdrawal_credentials = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.amount = (byte[]) eventValues.getNonIndexedValues().get(2).getValue(); + typedResponse.signature = (byte[]) eventValues.getNonIndexedValues().get(3).getValue(); + typedResponse.index = (byte[]) eventValues.getNonIndexedValues().get(4).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public Flowable depositEventEventFlowable(EthFilter filter) { + return web3j.ethLogFlowable(filter).map(new Function() { + @Override + public DepositEventEventResponse apply(Log log) { + Contract.EventValuesWithLog eventValues = extractEventParametersWithLog(DEPOSITEVENT_EVENT, log); + DepositEventEventResponse typedResponse = new DepositEventEventResponse(); + typedResponse.log = log; + typedResponse.pubkey = (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.withdrawal_credentials = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.amount = (byte[]) eventValues.getNonIndexedValues().get(2).getValue(); + typedResponse.signature = (byte[]) eventValues.getNonIndexedValues().get(3).getValue(); + typedResponse.index = (byte[]) eventValues.getNonIndexedValues().get(4).getValue(); + return typedResponse; + } + }); + } + + public Flowable depositEventEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(DEPOSITEVENT_EVENT)); + return depositEventEventFlowable(filter); + } + + public RemoteCall get_hash_tree_root() { + final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_GET_HASH_TREE_ROOT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, byte[].class); + } + + public RemoteCall get_deposit_count() { + final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_GET_DEPOSIT_COUNT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, byte[].class); + } + + public RemoteCall deposit(byte[] pubkey, byte[] withdrawal_credentials, byte[] signature, BigInteger weiValue) { + final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function( + FUNC_DEPOSIT, + Arrays.asList(new org.web3j.abi.datatypes.DynamicBytes(pubkey), + new org.web3j.abi.datatypes.DynamicBytes(withdrawal_credentials), + new org.web3j.abi.datatypes.DynamicBytes(signature)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function, weiValue); + } + + @Deprecated + public static DepositContract load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new DepositContract(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static DepositContract load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new DepositContract(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static DepositContract load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + return new DepositContract(contractAddress, web3j, credentials, contractGasProvider); + } + + public static DepositContract load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new DepositContract(contractAddress, web3j, transactionManager, contractGasProvider); + } + + public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + return deployRemoteCall(DepositContract.class, web3j, credentials, contractGasProvider, BINARY, ""); + } + + public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return deployRemoteCall(DepositContract.class, web3j, transactionManager, contractGasProvider, BINARY, ""); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return deployRemoteCall(DepositContract.class, web3j, credentials, gasPrice, gasLimit, BINARY, ""); + } + + @Deprecated + public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return deployRemoteCall(DepositContract.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, ""); + } + + public static class DepositEventEventResponse { + public Log log; + + public byte[] pubkey; + + public byte[] withdrawal_credentials; + + public byte[] amount; + + public byte[] signature; + + public byte[] index; + } +} diff --git a/pow/web3j/src/main/java/org/ethereum/beacon/pow/util/BloomFilter.java b/pow/web3j/src/main/java/org/ethereum/beacon/pow/util/BloomFilter.java new file mode 100644 index 000000000..646899412 --- /dev/null +++ b/pow/web3j/src/main/java/org/ethereum/beacon/pow/util/BloomFilter.java @@ -0,0 +1,70 @@ +package org.ethereum.beacon.pow.util; + +import java.util.Arrays; + +/** + * Bloom Filter function for ETH1 + */ +public class BloomFilter { + private final static int _8_STEPS = 8; + private final static int _3_LOW_BITS = 7; + private final static int ENSURE_BYTE = 255; + + private byte[] bytes; + + public BloomFilter(byte[] bytes) { + this.bytes = bytes; + } + + /** Creates bloom filter for provided topic. For address use address hash. */ + public static BloomFilter create(byte[] topic) { + int mov1 = (((topic[0] & ENSURE_BYTE) & (_3_LOW_BITS)) << _8_STEPS) + ((topic[1]) & ENSURE_BYTE); + int mov2 = (((topic[2] & ENSURE_BYTE) & (_3_LOW_BITS)) << _8_STEPS) + ((topic[3]) & ENSURE_BYTE); + int mov3 = (((topic[4] & ENSURE_BYTE) & (_3_LOW_BITS)) << _8_STEPS) + ((topic[5]) & ENSURE_BYTE); + + byte[] data = new byte[256]; + BloomFilter bloom = new BloomFilter(data); + setBit(data, mov1); + setBit(data, mov2); + setBit(data, mov3); + + return bloom; + } + + /** + * Sets bit to "true" (1) + */ + private static void setBit(byte[] data, int pos) { + int posByte = data.length - 1 - (pos / 8); + int posBit = pos % 8; + byte oldByte = data[posByte]; + byte newByte = (byte) (oldByte | 1 << posBit); + + data[posByte] = newByte; + } + + public BloomFilter or(BloomFilter bloom) { + byte[] copy = new byte[bytes.length]; + System.arraycopy(bytes, 0, copy, 0, bytes.length); + for (int i = 0; i < bytes.length; ++i) { + copy[i] |= bloom.bytes[i]; + } + + return new BloomFilter(copy); + } + + /** Checks whether this filter matches another = includes event from another filter */ + public boolean matches(BloomFilter topicBloom) { + return this.equals(this.or(topicBloom)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + BloomFilter that = (BloomFilter) o; + + return Arrays.equals(bytes, that.bytes); + } +} diff --git a/pow/web3j/src/test/java/org/ethereum/beacon/pow/AbstractWeb3JTest.java b/pow/web3j/src/test/java/org/ethereum/beacon/pow/AbstractWeb3JTest.java new file mode 100644 index 000000000..56275fdaa --- /dev/null +++ b/pow/web3j/src/test/java/org/ethereum/beacon/pow/AbstractWeb3JTest.java @@ -0,0 +1,124 @@ +package org.ethereum.beacon.pow; + +import io.reactivex.disposables.Disposable; +import org.ethereum.beacon.consensus.BeaconChainSpec; +import org.ethereum.beacon.core.spec.SpecConstants; +import org.ethereum.beacon.core.types.Time; +import org.ethereum.beacon.crypto.Hashes; +import org.ethereum.beacon.pow.contract.DepositContract; +import org.junit.Before; +import org.web3j.crypto.Credentials; +import org.web3j.crypto.Hash; +import org.web3j.protocol.admin.Admin; +import org.web3j.protocol.core.methods.response.EthBlock; +import org.web3j.protocol.core.methods.response.Transaction; +import org.web3j.protocol.http.HttpService; +import org.web3j.tx.gas.DefaultGasProvider; +import org.web3j.utils.Convert; +import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.uint.UInt64; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +/** + * Precondition: Start configured geth docker from "geth" directory in resources. It contains + * pre-mine for ALICE and required network settings to run deposit contract. + */ +public abstract class AbstractWeb3JTest { + private static final Credentials ALICE = + Credentials.create( + Hash.sha3(BytesValue.wrap("cow".getBytes()).toString()) // premined in genesis + ); + final int MERKLE_TREE_DEPTH = + BeaconChainSpec.DEFAULT_CONSTANTS.getDepositContractTreeDepth().intValue(); + final Function HASH_FUNCTION = Hashes::sha256; + BigInteger DEPOSIT_GWEI_AMOUNT = BigInteger.valueOf(32L * 1_000_000_000L); + BigInteger DEPOSIT_WEI_AMOUNT = + Convert.toWei(new BigDecimal(DEPOSIT_GWEI_AMOUNT), Convert.Unit.GWEI).toBigInteger(); + Admin web3j; + DepositContract contract; + Long contractDeployBlock; + + AbstractWeb3JTest() {} + + BeaconChainSpec createSpecNoBls() { + return new BeaconChainSpec.Builder() + .withDefaultHashFunction() + .withVerifyDepositProof(false) + .withBlsVerifyProofOfPossession(false) + .withConstants( + new SpecConstants() { + @Override + public UInt64 getMinGenesisActiveValidatorCount() { + return UInt64.valueOf(16); + } + + @Override + public Time getSecondsPerDay() { + return Time.of(5); + } + + @Override + public Time getMinGenesisTime() { + return Time.of(0); + } + }) + .withDefaultHasher() + .build(); + } + + BeaconChainSpec createSpecVerifyProof() { + return new BeaconChainSpec.Builder() + .withDefaultHashFunction() + .withVerifyDepositProof(true) + .withBlsVerifyProofOfPossession(true) + .withConstants( + new SpecConstants() { + @Override + public UInt64 getMinGenesisActiveValidatorCount() { + return UInt64.valueOf(16); + } + + @Override + public Time getSecondsPerDay() { + return Time.of(5); + } + + @Override + public Time getMinGenesisTime() { + return Time.of(0); + } + }) + .withDefaultHasher() + .build(); + } + + @Before + public void setUp() throws Exception { + this.web3j = Admin.build(new HttpService()); + Map allTxs = new HashMap<>(); + Disposable newBlockSub = + web3j + .blockFlowable(true) + .subscribe( + block -> { + for (EthBlock.TransactionResult txResult : block.getBlock().getTransactions()) { + Transaction tx = ((EthBlock.TransactionObject) txResult.get()).get(); + allTxs.put(tx.getHash(), block.getBlock().getNumber().longValue()); + } + }); + this.contract = DepositContract.deploy(web3j, ALICE, new DefaultGasProvider()).send(); + String txHash = contract.getTransactionReceipt().get().getTransactionHash(); + while (!allTxs.containsKey(txHash)) { + Thread.sleep(500); + } + this.contractDeployBlock = allTxs.get(txHash); + System.out.println("Contract deployed by tx in block #" + contractDeployBlock); + newBlockSub.dispose(); + } +} diff --git a/pow/web3j/src/test/java/org/ethereum/beacon/pow/BloomFilterTest.java b/pow/web3j/src/test/java/org/ethereum/beacon/pow/BloomFilterTest.java new file mode 100644 index 000000000..17c89ba87 --- /dev/null +++ b/pow/web3j/src/test/java/org/ethereum/beacon/pow/BloomFilterTest.java @@ -0,0 +1,28 @@ +package org.ethereum.beacon.pow; + +import org.ethereum.beacon.pow.util.BloomFilter; +import org.junit.Test; +import org.web3j.crypto.Hash; +import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import static org.junit.Assert.assertTrue; + +public class BloomFilterTest { + /** Some real-life data */ + @Test + public void test() { + String contractAddress = "0x99bde68864f63fde1df78ffa1808c232de7ef61e"; + BytesValue contractDeployAddress = BytesValue.fromHexString(contractAddress); + Hash32 contractDeployAddressHash = + Hash32.wrap(Bytes32.wrap(Hash.sha3(contractDeployAddress.extractArray()))); + BloomFilter contractAddressBloom = BloomFilter.create(contractDeployAddressHash.extractArray()); + BloomFilter blockLogsBloom = + new BloomFilter( + BytesValue.fromHexString( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000") + .extractArray()); + assertTrue(blockLogsBloom.matches(contractAddressBloom)); + } +} diff --git a/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractProofTest.java b/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractProofTest.java new file mode 100644 index 000000000..5ad3e9c46 --- /dev/null +++ b/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractProofTest.java @@ -0,0 +1,159 @@ +package org.ethereum.beacon.pow; + +import org.ethereum.beacon.consensus.BeaconChainSpec; +import org.ethereum.beacon.consensus.ChainStart; +import org.ethereum.beacon.core.BeaconState; +import org.ethereum.beacon.core.MutableBeaconState; +import org.ethereum.beacon.core.operations.Deposit; +import org.ethereum.beacon.core.operations.deposit.DepositData; +import org.ethereum.beacon.core.spec.SignatureDomains; +import org.ethereum.beacon.core.state.Eth1Data; +import org.ethereum.beacon.core.types.BLSPubkey; +import org.ethereum.beacon.core.types.BLSSignature; +import org.ethereum.beacon.core.types.Gwei; +import org.ethereum.beacon.crypto.BLS381; +import org.ethereum.beacon.crypto.MessageParameters; +import org.ethereum.beacon.crypto.util.BlsKeyPairGenerator; +import org.ethereum.beacon.schedulers.Schedulers; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.web3j.protocol.core.DefaultBlockParameter; +import org.web3j.protocol.core.methods.response.EthBlock; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import reactor.core.publisher.Mono; +import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.Bytes48; +import tech.pegasys.artemis.util.bytes.Bytes8; +import tech.pegasys.artemis.util.uint.UInt64; + +import java.math.BigInteger; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +/** + * Checks that deposit proofs are correct + * + *

See {@link AbstractWeb3JTest} for prerequisites + */ +@Ignore("Takes several minutes to run") +public class Web3JDepositContractProofTest extends AbstractWeb3JTest { + @Test + public void testVerifyProofs() throws Exception { + BeaconChainSpec specWithVerify = createSpecVerifyProof(); + BlsKeyPairGenerator generator = BlsKeyPairGenerator.createWithoutSeed(); + List eth1DataList = new ArrayList<>(); + long lastDepositBlock = 0; + for (int i = 0; i < 20; i++) { + BLS381.KeyPair keyPair = generator.next(); + Bytes48 pubKey = keyPair.getPublic().getEncodedBytes(); + Hash32 withdrawalCredentials = + Hash32.wrap(Bytes32.leftPad(UInt64.valueOf(i).toBytesBigEndian())); + + // Calculate signature + DepositData depositData = + new DepositData( + BLSPubkey.wrap(pubKey), + withdrawalCredentials, + Gwei.castFrom(UInt64.valueOf(DEPOSIT_GWEI_AMOUNT.longValue())), + BLSSignature.ZERO); + MessageParameters messageParameters = + MessageParameters.create( + specWithVerify.signing_root(depositData), SignatureDomains.DEPOSIT); + BLS381.Signature signature = BLS381.sign(messageParameters, keyPair); + + // Send deposit + final TransactionReceipt receipt = + contract + .deposit( + pubKey.extractArray(), + withdrawalCredentials.extractArray(), + signature.getEncoded().extractArray(), + DEPOSIT_WEI_AMOUNT) + .send(); + + Assert.assertTrue(receipt.isStatusOK()); + Assert.assertEquals(1, receipt.getLogs().size()); + lastDepositBlock = receipt.getBlockNumber().longValue(); + + // Store Eth1 for this deposit in list + byte[] depositRoot = contract.get_hash_tree_root().send(); + byte[] depositCount = contract.get_deposit_count().send(); + Eth1Data lastDepositEthData = + new Eth1Data( + Hash32.wrap(Bytes32.wrap((depositRoot))), + UInt64.fromBytesLittleEndian(Bytes8.wrap((depositCount))), + Hash32.ZERO); + eth1DataList.add(lastDepositEthData); + + System.out.println( + String.format( + "root %d: %s", + lastDepositEthData.getDepositCount().decrement().getValue(), + lastDepositEthData.getDepositRoot())); + } + + // skip contract signature verification + BeaconChainSpec specWithoutVerify = createSpecNoBls(); + Web3JDepositContract depositContract = + new Web3JDepositContract( + web3j, + contract.getContractAddress(), + contractDeployBlock, + Schedulers.createDefault(), + HASH_FUNCTION, + MERKLE_TREE_DEPTH, + specWithoutVerify); + depositContract.setDistanceFromHead(3); + + ChainStart chainStart = + Mono.from(depositContract.getChainStartMono()).block(Duration.ofSeconds(60)); + Assert.assertEquals(16, chainStart.getInitialDeposits().size()); + MutableBeaconState beaconState = BeaconState.getEmpty().createMutableCopy(); + beaconState.setEth1Data(chainStart.getEth1Data()); + for (Deposit deposit : chainStart.getInitialDeposits()) { + // The proof for each deposit must be constructed against the deposit root contained in + // state.latest_eth1_data rather than the deposit root at the time the deposit was initially + // logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and + // computing updated proofs against the latest_eth1_data.deposit_root as needed. See + // minimal_merkle.py for a sample implementation. + specWithVerify.verify_deposit(beaconState, deposit); + specWithVerify.process_deposit(beaconState, deposit); + } + + // wait until block lastValidatorDeposit + 5 appears in network + EthBlock.Block eth1Block = null; + while (eth1Block == null) { + eth1Block = + web3j + .ethGetBlockByNumber( + DefaultBlockParameter.valueOf(BigInteger.valueOf(lastDepositBlock + 5)), false) + .send() + .getBlock(); + if (eth1Block == null) { + Thread.sleep(200); + } + } + + byte[] depositRoot = contract.get_hash_tree_root().send(); + Eth1Data lastDepositEthData = + new Eth1Data( + Hash32.wrap(Bytes32.wrap(depositRoot)), + UInt64.ZERO, + Hash32.wrap(Bytes32.fromHexString(eth1Block.getHash()))); + + List depositInfos1 = + depositContract.peekDeposits(100, chainStart.getEth1Data(), lastDepositEthData); + + // Verify remaining deposits + Assert.assertEquals(4, depositInfos1.size()); + for (org.ethereum.beacon.pow.DepositContract.DepositInfo depositInfo : depositInfos1) { + beaconState.setEth1Data( + eth1DataList.get(depositInfo.getEth1Data().getDepositCount().decrement().intValue())); + specWithVerify.verify_deposit(beaconState, depositInfo.getDeposit()); + specWithVerify.process_deposit(beaconState, depositInfo.getDeposit()); + } + } +} diff --git a/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractRootTest.java b/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractRootTest.java new file mode 100644 index 000000000..c9e1195c4 --- /dev/null +++ b/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractRootTest.java @@ -0,0 +1,116 @@ +package org.ethereum.beacon.pow; + +import org.ethereum.beacon.consensus.ChainStart; +import org.ethereum.beacon.schedulers.Schedulers; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import reactor.core.publisher.Mono; +import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.Bytes8; +import tech.pegasys.artemis.util.bytes.Bytes96; +import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.bytes.MutableBytes48; +import tech.pegasys.artemis.util.uint.UInt64; + +import java.time.Duration; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.Assert.assertEquals; + +/** + * Checks that deposit root from contract and merkle tree matches each other + * + *

See {@link AbstractWeb3JTest} for prerequisites + */ +@Ignore("Takes several minutes to run") +public class Web3JDepositContractRootTest extends AbstractWeb3JTest { + @Test + public void testVerifyDepositRoot() throws Exception { + AtomicLong latestProcessedBlock = new AtomicLong(0); + byte[] latestCalculatedDepositRoot = new byte[32]; + Web3JDepositContract depositContract = + new Web3JDepositContract( + web3j, + contract.getContractAddress(), + contractDeployBlock, + Schedulers.createDefault(), + HASH_FUNCTION, + MERKLE_TREE_DEPTH, + createSpecNoBls()) { + + // avoid async block processing + @Override + protected void processConfirmedBlocks() { + long bestConfirmedBlock = getBestConfirmedBlock(); + processBlocksUpTo(bestConfirmedBlock); + latestProcessedBlock.set(bestConfirmedBlock); + } + + // store deposit root in latestCalculatedDepositRoot + @Override + protected synchronized void newDeposits( + List eventDataList, byte[] blockHash, long blockTimestamp) { + super.newDeposits(eventDataList, blockHash, blockTimestamp); + for (DepositEventData eventData : eventDataList) { + System.arraycopy( + getDepositRoot(eventData.index).extractArray(), + 0, + latestCalculatedDepositRoot, + 0, + 32); + } + } + }; + depositContract.setDistanceFromHead(3); + // Fire contract handling + Mono.from(depositContract.getChainStartMono()) + .subscribe(chainStart -> System.out.println("Chain started!")); + + // Check that contract deployed successfully and is empty + final byte[] depositCount = contract.get_deposit_count().send(); + assertEquals( + UInt64.ZERO, UInt64.fromBytesLittleEndian(Bytes8.rightPad(BytesValue.wrap(depositCount)))); + final byte[] hashTreeRoot = contract.get_hash_tree_root().send(); + assertEquals( + Hash32.fromHexString("0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e"), + Hash32.wrap(Bytes32.wrap(hashTreeRoot))); + + // Submit deposits from several validators + for (int i = 0; i < 20; i++) { + MutableBytes48 pubKey = MutableBytes48.create(); + pubKey.set(0, (byte) i); + + final TransactionReceipt receipt = + contract + .deposit( + pubKey.extractArray(), + Hash32.ZERO.extractArray(), + Bytes96.ZERO.extractArray(), + DEPOSIT_WEI_AMOUNT) + .send(); + Assert.assertTrue(receipt.isStatusOK()); + Assert.assertEquals(1, receipt.getLogs().size()); + + // wait for block processing + long depositBlock = receipt.getBlockNumber().longValue(); + while (depositBlock > latestProcessedBlock.get()) { + Thread.sleep(200); + } + byte[] depositRoot = contract.get_hash_tree_root().send(); + Assert.assertArrayEquals(depositRoot, latestCalculatedDepositRoot); + System.out.println(String.format("Validator #%s submitted its deposit", i)); + } + + ChainStart chainStart = + Mono.from(depositContract.getChainStartMono()).block(Duration.ofSeconds(60)); + Assert.assertEquals(16, chainStart.getInitialDeposits().size()); + for (int i = 0; i < 16; i++) { + Assert.assertEquals( + (byte) i, chainStart.getInitialDeposits().get(i).getData().getPubKey().get(0)); + } + } +} diff --git a/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractTest.java b/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractTest.java new file mode 100644 index 000000000..72f97d06a --- /dev/null +++ b/pow/web3j/src/test/java/org/ethereum/beacon/pow/Web3JDepositContractTest.java @@ -0,0 +1,127 @@ +package org.ethereum.beacon.pow; + +import org.ethereum.beacon.consensus.ChainStart; +import org.ethereum.beacon.core.state.Eth1Data; +import org.ethereum.beacon.schedulers.Schedulers; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.web3j.protocol.core.DefaultBlockParameter; +import org.web3j.protocol.core.methods.response.EthBlock; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import reactor.core.publisher.Mono; +import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.Bytes8; +import tech.pegasys.artemis.util.bytes.Bytes96; +import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.bytes.MutableBytes48; +import tech.pegasys.artemis.util.uint.UInt64; + +import java.math.BigInteger; +import java.time.Duration; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * General test: submit 20 deposits, chain starts on 16, checks that contract handled it as it + * should + * + *

See {@link AbstractWeb3JTest} for prerequisites + */ +@Ignore("Takes several minutes to run") +public class Web3JDepositContractTest extends AbstractWeb3JTest { + @Test + public void test1() throws Exception { + // Check that contract deployed successfully and is empty + final byte[] depositCount = contract.get_deposit_count().send(); + assertEquals( + UInt64.ZERO, UInt64.fromBytesLittleEndian(Bytes8.rightPad(BytesValue.wrap(depositCount)))); + final byte[] hashTreeRoot = contract.get_hash_tree_root().send(); + assertEquals( + Hash32.fromHexString("0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e"), + Hash32.wrap(Bytes32.wrap(hashTreeRoot))); + + // Submit deposits from several validators + long lastDepositBlock = 0; + for (int i = 0; i < 20; i++) { + MutableBytes48 pubKey = MutableBytes48.create(); + pubKey.set(0, (byte) i); + + final TransactionReceipt receipt = + contract + .deposit( + pubKey.extractArray(), + Hash32.ZERO.extractArray(), + Bytes96.ZERO.extractArray(), + DEPOSIT_WEI_AMOUNT) + .send(); + + Assert.assertTrue(receipt.isStatusOK()); + Assert.assertEquals(1, receipt.getLogs().size()); + lastDepositBlock = receipt.getBlockNumber().longValue(); + System.out.println(String.format("Validator #%s submitted its deposit", i)); + } + + Web3JDepositContract depositContract = + new Web3JDepositContract( + web3j, + contract.getContractAddress(), + contractDeployBlock, + Schedulers.createDefault(), + HASH_FUNCTION, + MERKLE_TREE_DEPTH, + createSpecNoBls()); + depositContract.setDistanceFromHead(3); + + ChainStart chainStart = + Mono.from(depositContract.getChainStartMono()).block(Duration.ofSeconds(60)); + + // 16 deposits until chain start according to spec + Assert.assertEquals(16, chainStart.getInitialDeposits().size()); + for (int i = 0; i < 16; i++) { + Assert.assertEquals( + (byte) i, chainStart.getInitialDeposits().get(i).getData().getPubKey().get(0)); + } + + // wait until block lastValidatorDeposit + 5 appears in network + EthBlock.Block eth1Block = null; + while (eth1Block == null) { + eth1Block = + web3j + .ethGetBlockByNumber( + DefaultBlockParameter.valueOf(BigInteger.valueOf(lastDepositBlock + 5)), false) + .send() + .getBlock(); + if (eth1Block == null) { + Thread.sleep(200); + } + } + + byte[] depositRoot = contract.get_hash_tree_root().send(); + Eth1Data lastDepositEthData = + new Eth1Data( + Hash32.wrap(Bytes32.wrap(depositRoot)), + UInt64.ZERO, + Hash32.wrap(Bytes32.fromHexString(eth1Block.getHash()))); + + // we have 4 after chain start, so we are able to get 2 + List depositInfos1 = + depositContract.peekDeposits(2, chainStart.getEth1Data(), lastDepositEthData); + Assert.assertEquals(2, depositInfos1.size()); + Assert.assertEquals((byte) 16, depositInfos1.get(0).getDeposit().getData().getPubKey().get(0)); + Assert.assertEquals((byte) 17, depositInfos1.get(1).getDeposit().getData().getPubKey().get(0)); + + // and another 2. and that's all + List depositInfos2 = + depositContract.peekDeposits(200, depositInfos1.get(1).getEth1Data(), lastDepositEthData); + Assert.assertEquals(2, depositInfos2.size()); + Assert.assertEquals((byte) 18, depositInfos2.get(0).getDeposit().getData().getPubKey().get(0)); + Assert.assertEquals((byte) 19, depositInfos2.get(1).getDeposit().getData().getPubKey().get(0)); + + List depositInfos3 = + depositContract.peekDeposits(200, lastDepositEthData, lastDepositEthData); + Assert.assertEquals(0, depositInfos3.size()); + } +} diff --git a/pow/web3j/src/test/resources/geth/Dockerfile b/pow/web3j/src/test/resources/geth/Dockerfile new file mode 100644 index 000000000..2df1c8711 --- /dev/null +++ b/pow/web3j/src/test/resources/geth/Dockerfile @@ -0,0 +1,23 @@ +# Build Geth in a stock Go builder container +FROM golang:1.12-alpine as builder + +RUN apk add --no-cache make gcc musl-dev linux-headers git + +ARG branch=master +RUN git clone --depth 1 --branch $branch https://github.com/ethereum/go-ethereum.git + +ADD . /go-ethereum +RUN cd /go/go-ethereum && make geth + +# Pull Geth into a second stage deploy alpine container +FROM alpine:latest + +RUN apk add --no-cache ca-certificates bash +COPY --from=builder /go/go-ethereum/build/bin/geth /usr/local/bin/ + +ADD genesis.json /genesis.json +ADD geth.sh /geth.sh +RUN chmod +x /geth.sh + +EXPOSE 8545 8546 30303 30303/udp +ENTRYPOINT ["/geth.sh"] diff --git a/pow/web3j/src/test/resources/geth/README.md b/pow/web3j/src/test/resources/geth/README.md new file mode 100644 index 000000000..36c5450aa --- /dev/null +++ b/pow/web3j/src/test/resources/geth/README.md @@ -0,0 +1,14 @@ +Go-Ethereum instance with open RPC and non-persistent DB initialized with `genesis.json`. + +Building image: +```shell script +docker build . +``` +Running container: +```shell script +docker run -d -p 8545:8545 -p 30303:30303 +``` +Stopping and removing container +```shell script +docker rm -f +``` diff --git a/pow/web3j/src/test/resources/geth/genesis.json b/pow/web3j/src/test/resources/geth/genesis.json new file mode 100644 index 000000000..c9d22c0ff --- /dev/null +++ b/pow/web3j/src/test/resources/geth/genesis.json @@ -0,0 +1,18 @@ +{ + "config": { + "chainId": 15, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0 + }, + "difficulty": "2", + "gasLimit": "8000000", + "alloc": { + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "40000000000000000000000" }, + "e4e3b50829d2121c2afe5352568c18606c93e38e": { "balance": "40000000000000000000000" } + } +} diff --git a/pow/web3j/src/test/resources/geth/geth.sh b/pow/web3j/src/test/resources/geth/geth.sh new file mode 100755 index 000000000..6f295def9 --- /dev/null +++ b/pow/web3j/src/test/resources/geth/geth.sh @@ -0,0 +1,8 @@ +#!/bin/bash +#set -e +echo "Init DB with genesis.json" +geth --datadir test init genesis.json +echo "Start geth" +geth --datadir test --networkid 15 --rpcapi personal,db,eth,net,web3 --rpc --rpcaddr 0.0.0.0 \ + --mine --minerthreads=1 --gasprice=1 --etherbase=0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826 \ + --nodiscover --maxpeers 0 \ No newline at end of file diff --git a/pow/web3j/src/test/resources/log4j2.xml b/pow/web3j/src/test/resources/log4j2.xml new file mode 100644 index 000000000..39a719df5 --- /dev/null +++ b/pow/web3j/src/test/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + %d{HH:mm:ss.SSS} %-5level - %msg%n + + + + + + + + + diff --git a/settings.gradle b/settings.gradle index b83a97b7d..1e5cef738 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,7 @@ include 'pow:core' include 'pow:ethereumj' // PoW validator part include 'pow:validator' -// PoW made with web3j (not ready yet) +// PoW made with web3j include 'pow:web3j' // SSZ (Simple serialization) include 'ssz' diff --git a/versions.gradle b/versions.gradle index d934da377..9cfea04ae 100644 --- a/versions.gradle +++ b/versions.gradle @@ -9,7 +9,9 @@ dependencyManagement { dependency "org.apache.logging.log4j:log4j-api:${log4j2Version}" dependency "org.apache.logging.log4j:log4j-core:${log4j2Version}" + dependency "org.slf4j:slf4j-simple:1.7.28" dependency 'org.ethereum:ethereumj-core:1+' + dependency "org.web3j:core:4.2.0" dependency 'org.bouncycastle:bcprov-jdk15on:1.60' dependency 'org.miracl.milagro.amcl:milagro-crypto-java:0.4.0' From 511bd4bfbe820ba2c027d2525e193c1586c15f1f Mon Sep 17 00:00:00 2001 From: Dmitrii Shmatko Date: Thu, 15 Aug 2019 14:03:26 +0300 Subject: [PATCH 3/3] core: fixed BeaconState interface were not accessible --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index a2172e03a..9e34c2cbc 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,7 +1,7 @@ dependencies { implementation project(':types') implementation project(':crypto') - implementation project(':ssz') + api project(':ssz') implementation 'com.google.guava:guava'