/* * Copyright 2019 Web3 Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package org.web3j.protocol.besu; import java.io.IOException; import java.math.BigInteger; import java.util.Arrays; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.web3j.crypto.Credentials; import org.web3j.crypto.Sign; import org.web3j.crypto.TransactionEncoder; import org.web3j.generated.HumanStandardToken; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.protocol.besu.response.privacy.PrivateTransactionWithPrivacyGroup; import org.web3j.protocol.eea.crypto.PrivateTransactionEncoder; import org.web3j.protocol.eea.crypto.RawPrivateTransaction; import org.web3j.protocol.http.HttpService; import org.web3j.tx.BesuPrivateTransactionManager; import org.web3j.tx.LegacyPrivateTransactionManager; import org.web3j.tx.PrivateTransactionManager; import org.web3j.tx.gas.BesuPrivacyGasProvider; import org.web3j.tx.response.PollingPrivateTransactionReceiptProcessor; import org.web3j.utils.Base64String; import org.web3j.utils.Numeric; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.web3j.utils.Restriction.RESTRICTED; /** * Test designed to run with besu-quickstart https://github.com/PegaSysEng/besu-quickstart Using * orion 1.3.2 */ @Disabled public class BesuPrivacyQuickstartIntegrationTest { private static final String CLIENT_VERSION = "besu/v1.3.0/linux-x86_64/oracle_openjdk-java-11"; // FIXME: This should be made public in the contract wrapper private static final String HUMAN_STANDARD_TOKEN_BINARY = "60c0604052600460808190527f48302e310000000000000000000000000000000000000000000000000000000060a090815261003e91600691906100d0565b5034801561004b57600080fd5b506040516109ab3803806109ab8339810160409081528151602080840151838501516060860151336000908152600185529586208590559484905590850180519395909491939101916100a3916003918601906100d0565b506004805460ff191660ff841617905580516100c69060059060208401906100d0565b505050505061016b565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061011157805160ff191683800117855561013e565b8280016001018555821561013e579182015b8281111561013e578251825591602001919060010190610123565b5061014a92915061014e565b5090565b61016891905b8082111561014a5760008155600101610154565b90565b6108318061017a6000396000f3006080604052600436106100955763ffffffff60e060020a60003504166306fdde0381146100a7578063095ea7b31461013157806318160ddd1461016957806323b872dd14610190578063313ce567146101ba57806354fd4d50146101e557806370a08231146101fa57806395d89b411461021b578063a9059cbb14610230578063cae9ca5114610254578063dd62ed3e146102bd575b3480156100a157600080fd5b50600080fd5b3480156100b357600080fd5b506100bc6102e4565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100f65781810151838201526020016100de565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013d57600080fd5b50610155600160a060020a0360043516602435610372565b604080519115158252519081900360200190f35b34801561017557600080fd5b5061017e6103d9565b60408051918252519081900360200190f35b34801561019c57600080fd5b50610155600160a060020a03600435811690602435166044356103df565b3480156101c657600080fd5b506101cf6104cc565b6040805160ff9092168252519081900360200190f35b3480156101f157600080fd5b506100bc6104d5565b34801561020657600080fd5b5061017e600160a060020a0360043516610530565b34801561022757600080fd5b506100bc61054b565b34801561023c57600080fd5b50610155600160a060020a03600435166024356105a6565b34801561026057600080fd5b50604080516020600460443581810135601f8101849004840285018401909552848452610155948235600160a060020a031694602480359536959460649492019190819084018382808284375094975061063f9650505050505050565b3480156102c957600080fd5b5061017e600160a060020a03600435811690602435166107da565b6003805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561036a5780601f1061033f5761010080835404028352916020019161036a565b820191906000526020600020905b81548152906001019060200180831161034d57829003601f168201915b505050505081565b336000818152600260209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60005481565b600160a060020a038316600090815260016020526040812054821180159061042a5750600160a060020a03841660009081526002602090815260408083203384529091529020548211155b80156104365750600082115b156104c157600160a060020a03808416600081815260016020908152604080832080548801905593881680835284832080548890039055600282528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060016104c5565b5060005b9392505050565b60045460ff1681565b6006805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561036a5780601f1061033f5761010080835404028352916020019161036a565b600160a060020a031660009081526001602052604090205490565b6005805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561036a5780601f1061033f5761010080835404028352916020019161036a565b3360009081526001602052604081205482118015906105c55750600082115b156106375733600081815260016020908152604080832080548790039055600160a060020a03871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35060016103d3565b5060006103d3565b336000818152600260209081526040808320600160a060020a038816808552908352818420879055815187815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a383600160a060020a031660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e019050604051809103902060e060020a9004338530866040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184815260200183600160a060020a0316600160a060020a03168152602001828051906020019080838360005b8381101561077f578181015183820152602001610767565b50505050905090810190601f1680156107ac5780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000875af19250505015156107d057600080fd5b5060019392505050565b600160a060020a039182166000908152600260209081526040808320939094168252919091522054905600a165627a7a723058203f2de808df5359509254dc2a0d616b226de2b64f0bf28bae7323aeba4487199b0029"; private static final Credentials ALICE = Credentials.create("8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"); private static final Credentials BOB = Credentials.create("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3"); private static final Credentials CHARLIE = Credentials.create("ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f"); private static final Base64String ENCLAVE_KEY_ALICE = Base64String.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="); private static final Base64String ENCLAVE_KEY_BOB = Base64String.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="); private static final Base64String ENCLAVE_KEY_CHARLIE = Base64String.wrap("k2zXEin4Ip/qBGlRkJejnGWdP9cjkK+DAvKNW31L2C8="); private static final BesuPrivacyGasProvider ZERO_GAS_PROVIDER = new BesuPrivacyGasProvider(BigInteger.valueOf(0)); private static Besu nodeAlice; private static Besu nodeBob; private static Besu nodeCharlie; @BeforeAll public static void setUpOnce() { nodeAlice = Besu.build(new HttpService("http://localhost:20000")); nodeBob = Besu.build(new HttpService("http://localhost:20002")); nodeCharlie = Besu.build(new HttpService("http://localhost:20004")); } @Test public void testConnection() throws IOException { assertEquals(nodeAlice.web3ClientVersion().send().getWeb3ClientVersion(), (CLIENT_VERSION)); assertEquals(nodeBob.web3ClientVersion().send().getWeb3ClientVersion(), (CLIENT_VERSION)); assertEquals( nodeCharlie.web3ClientVersion().send().getWeb3ClientVersion(), (CLIENT_VERSION)); } @Test public void simplePrivateTransactions() throws Exception { // Build new privacy group using the create API final Base64String privacyGroupId = nodeBob.privCreatePrivacyGroup( Arrays.asList( ENCLAVE_KEY_ALICE, ENCLAVE_KEY_BOB, ENCLAVE_KEY_CHARLIE), "AliceBobCharlie", "AliceBobCharlie group") .send() .getPrivacyGroupId(); final BigInteger nonce = nodeCharlie .privGetTransactionCount(ALICE.getAddress(), privacyGroupId) .send() .getTransactionCount(); final RawPrivateTransaction rawPrivateTransaction = RawPrivateTransaction.createContractTransaction( nonce, ZERO_GAS_PROVIDER.getGasPrice(), ZERO_GAS_PROVIDER.getGasLimit(), HUMAN_STANDARD_TOKEN_BINARY, ENCLAVE_KEY_ALICE, privacyGroupId, RESTRICTED); final String signedTransactionData = Numeric.toHexString( PrivateTransactionEncoder.signMessage(rawPrivateTransaction, 2018, ALICE)); final String transactionHash = nodeAlice.eeaSendRawTransaction(signedTransactionData).send().getTransactionHash(); final PollingPrivateTransactionReceiptProcessor receiptProcessor = new PollingPrivateTransactionReceiptProcessor(nodeAlice, 1 * 1000, 120); final PrivateTransactionReceipt receipt = receiptProcessor.waitForTransactionReceipt(transactionHash); assertEquals(receipt.getFrom(), (ALICE.getAddress())); assertEquals(receipt.getLogs().size(), (0)); assertNull(receipt.getTo()); assertNotNull(receipt.getContractAddress()); assertNotNull(receipt.getStatus()); assertNull(receipt.getRevertReason()); final PrivateTransactionWithPrivacyGroup privateTransaction = (PrivateTransactionWithPrivacyGroup) nodeAlice .privGetPrivateTransaction(transactionHash) .send() .getPrivateTransaction() .get(); assertEquals(privateTransaction.getFrom(), (ALICE.getAddress())); assertEquals(privateTransaction.getGas(), (ZERO_GAS_PROVIDER.getGasLimit())); assertEquals(privateTransaction.getGasPrice(), (ZERO_GAS_PROVIDER.getGasPrice())); assertEquals(privateTransaction.getNonce(), (nonce)); final byte[] encodedTransaction = PrivateTransactionEncoder.encode(rawPrivateTransaction, 2018); final Sign.SignatureData signatureData = Sign.signMessage(encodedTransaction, ALICE.getEcKeyPair()); final Sign.SignatureData eip155SignatureData = TransactionEncoder.createEip155SignatureData(signatureData, 2018); assertEquals( Numeric.toBytesPadded(BigInteger.valueOf(privateTransaction.getV()), 2), (eip155SignatureData.getV())); assertEquals( Numeric.hexStringToByteArray(privateTransaction.getR()), (eip155SignatureData.getR())); assertEquals( Numeric.hexStringToByteArray(privateTransaction.getS()), (eip155SignatureData.getS())); assertEquals(privateTransaction.getPrivateFrom(), (ENCLAVE_KEY_ALICE)); assertEquals(privateTransaction.getPrivacyGroupId(), (privacyGroupId)); assertEquals(privateTransaction.getRestriction(), (RESTRICTED)); assertNull(privateTransaction.getTo()); } @Test public void legacyContract() throws Exception { final PrivateTransactionManager tmAlice = new LegacyPrivateTransactionManager( nodeAlice, ZERO_GAS_PROVIDER, ALICE, 2018, ENCLAVE_KEY_ALICE, Arrays.asList(ENCLAVE_KEY_BOB)); final PrivateTransactionManager tmBob = new LegacyPrivateTransactionManager( nodeBob, ZERO_GAS_PROVIDER, BOB, 2018, ENCLAVE_KEY_BOB, Arrays.asList(ENCLAVE_KEY_ALICE)); final HumanStandardToken tokenAlice = HumanStandardToken.deploy( nodeAlice, tmAlice, ZERO_GAS_PROVIDER, BigInteger.TEN, "eea_token", BigInteger.TEN, "EEATKN") .send(); final HumanStandardToken tokenBob = HumanStandardToken.load( tokenAlice.getContractAddress(), nodeBob, tmBob, ZERO_GAS_PROVIDER); tokenAlice.transfer(BOB.getAddress(), BigInteger.TEN).send(); testBalances(tokenAlice, tokenBob, BigInteger.ZERO, BigInteger.TEN); } @Test public void privacyGroupContract() throws Exception { // Build new privacy group using the create API final Base64String aliceBobGroup = nodeAlice .privCreatePrivacyGroup( Arrays.asList(ENCLAVE_KEY_ALICE, ENCLAVE_KEY_BOB), "AliceBob", "AliceBob group") .send() .getPrivacyGroupId(); // Find the privacy group that was built by Alice from Bob's node final Base64String aliceBobGroupFromBobNode = nodeBob.privFindPrivacyGroup(Arrays.asList(ENCLAVE_KEY_ALICE, ENCLAVE_KEY_BOB)) .send().getGroups().stream() .filter( g -> g.getName().equals("AliceBob") && g.getDescription().equals("AliceBob group") && g.getPrivacyGroupId().equals(aliceBobGroup)) .findFirst() .orElseThrow(RuntimeException::new) .getPrivacyGroupId(); final PrivateTransactionManager tmAlice = new BesuPrivateTransactionManager( nodeAlice, ZERO_GAS_PROVIDER, ALICE, 2018, ENCLAVE_KEY_ALICE, aliceBobGroup); final PrivateTransactionManager tmBob = new BesuPrivateTransactionManager( nodeBob, ZERO_GAS_PROVIDER, BOB, 2018, ENCLAVE_KEY_BOB, aliceBobGroupFromBobNode); final HumanStandardToken tokenAlice = HumanStandardToken.deploy( nodeAlice, tmAlice, ZERO_GAS_PROVIDER, BigInteger.TEN, "eea_token", BigInteger.TEN, "EEATKN") .send(); final HumanStandardToken tokenBob = HumanStandardToken.load( tokenAlice.getContractAddress(), nodeBob, tmBob, ZERO_GAS_PROVIDER); tokenAlice.transfer(BOB.getAddress(), BigInteger.TEN).send(); testBalances(tokenAlice, tokenBob, BigInteger.ZERO, BigInteger.TEN); } private void testBalances( final HumanStandardToken tokenAlice, final HumanStandardToken tokenBob, final BigInteger aliceBalance, final BigInteger bobBalance) throws Exception { final BigInteger aliceAlice = tokenAlice.balanceOf(ALICE.getAddress()).send(); final BigInteger aliceBob = tokenAlice.balanceOf(BOB.getAddress()).send(); final BigInteger bobAlice = tokenBob.balanceOf(ALICE.getAddress()).send(); final BigInteger bobBob = tokenBob.balanceOf(BOB.getAddress()).send(); assertEquals(aliceAlice, (aliceBalance)); assertEquals(aliceBob, (bobBalance)); assertEquals(bobAlice, (aliceBalance)); assertEquals(bobBob, (bobBalance)); } }