1+ /*******************************************************************************
2+ * Copyright (c) 2019-2022 Institute for the Architecture of Application System - University of Stuttgart
3+ * Author: Ghareeb Falazi
4+ * Co-author: Akshay Patel
5+ *
6+ * This program and the accompanying materials are made available under the
7+ * terms the Apache Software License 2.0
8+ * which is available at https://www.apache.org/licenses/LICENSE-2.0.
9+ *
10+ * SPDX-License-Identifier: Apache-2.0
11+ *******************************************************************************/
12+ package blockchains .iaas .uni .stuttgart .de .plugin .ethereum ;
13+
14+ import java .io .File ;
15+ import java .io .IOException ;
16+ import java .math .BigDecimal ;
17+ import java .math .BigInteger ;
18+ import java .nio .charset .StandardCharsets ;
19+ import java .time .Duration ;
20+ import java .time .LocalDateTime ;
21+ import java .util .*;
22+ import java .util .concurrent .ExecutionException ;
23+
24+ import blockchains .iaas .uni .stuttgart .de .api .model .LinearChainTransaction ;
25+ import blockchains .iaas .uni .stuttgart .de .api .model .Parameter ;
26+ import blockchains .iaas .uni .stuttgart .de .api .model .Transaction ;
27+
28+ import blockchains .iaas .uni .stuttgart .de .api .utils .PoWConfidenceCalculator ;
29+ import blockchains .iaas .uni .stuttgart .de .plugin .ethereum .contracts .Permissions ;
30+ import org .junit .jupiter .api .Assertions ;
31+ import org .junit .jupiter .api .BeforeAll ;
32+ import org .junit .jupiter .api .BeforeEach ;
33+ import org .junit .jupiter .api .Disabled ;
34+ import org .junit .jupiter .api .Test ;
35+ import org .slf4j .Logger ;
36+ import org .slf4j .LoggerFactory ;
37+ import org .web3j .crypto .CipherException ;
38+ import org .web3j .crypto .ECKeyPair ;
39+ import org .web3j .crypto .WalletUtils ;
40+ import org .web3j .tx .gas .DefaultGasProvider ;
41+
42+ /**
43+ * To run these tests, you need ganache with the following mnemonic:
44+ * smart contract composition
45+ */
46+ class EthereumAdapterTest {
47+ private static final String NETWORK_NAME = "eth-0" ;
48+ private static final String MESSAGE = "This was not a difficult task!" ;
49+ private final String BYTES_TYPE = "{\n " +
50+ "\t \" type\" : \" array\" ,\n " +
51+ "\t \" items\" : {\n " +
52+ "\t \t \" type\" : \" string\" ,\n " +
53+ "\t \t \" pattern\" : \" ^[a-fA-F0-9]{2}$\" \n " +
54+ "\t }\n " +
55+ "}" ;
56+ private final String ADDRESS_TYPE = "{\n " +
57+ "\t \" type\" : \" string\" ,\n " +
58+ "\t \" pattern\" : \" ^0x[a-fA-F0-9]{40}$\" \n " +
59+ "}" ;
60+ private static final double REQUIRED_CONFIDENCE = 0.01 ;
61+ private EthereumAdapter adapter ;
62+ private static final Logger log = LoggerFactory .getLogger (EthereumAdapterTest .class );
63+
64+ @ BeforeEach
65+ void init () {
66+ this .adapter = getAdapter ();
67+ }
68+
69+ @ Test
70+ void testConnectionToNode () {
71+ Assertions .assertEquals ("true" , this .adapter .testConnectionToNode ());
72+ }
73+
74+ @ Test
75+ void testSendTransaction () throws ExecutionException , InterruptedException {
76+ final String toAddress = "0x182761AC584C0016Cdb3f5c59e0242EF9834fef0" ;
77+ final BigDecimal value = new BigDecimal (5000 );
78+ LinearChainTransaction result = (LinearChainTransaction ) this .adapter .submitTransaction (toAddress , value , REQUIRED_CONFIDENCE ).get ();
79+ log .debug ("transaction hash is: " + result .getTransactionHash ());
80+ }
81+
82+ @ Test
83+ void testInvokeSmartContract () throws Exception {
84+ Permissions contract = this .deployContract ();
85+ String smartContractPath = contract .getContractAddress ();
86+ String functionIdentifier = "setPublicKey" ;
87+ byte [] bytes = MESSAGE .getBytes ();
88+ String argument = new BigInteger (bytes ).toString (16 );
89+ List <Parameter > inputs = Collections .singletonList (new Parameter ("publicKey" , BYTES_TYPE , argument ));
90+ List <Parameter > outputs = Collections .emptyList ();
91+ LinearChainTransaction init = (LinearChainTransaction ) this .adapter .invokeSmartContract (smartContractPath , functionIdentifier , inputs , outputs , REQUIRED_CONFIDENCE , 100000000 ).get ();
92+ log .info ("initial transaction {}" , init .getTransactionHash ());
93+ functionIdentifier = "getPublicKey" ;
94+ inputs = Collections .singletonList (new Parameter ("ethereumAddress" , ADDRESS_TYPE , "0x90645Dc507225d61cB81cF83e7470F5a6AA1215A" ));
95+ outputs = Collections .singletonList (new Parameter ("return" , BYTES_TYPE , null ));
96+ Transaction result = this .adapter .invokeSmartContract (smartContractPath , functionIdentifier , inputs , outputs , REQUIRED_CONFIDENCE , 0 ).get ();
97+ String value = result .getReturnValues ().get (0 ).getValue ();
98+ log .debug (value );
99+ String retrievedMessage = new String (new BigInteger (value , 16 ).toByteArray (), StandardCharsets .UTF_8 );
100+ Assertions .assertEquals (MESSAGE , retrievedMessage );
101+ log .debug (retrievedMessage );
102+ }
103+
104+ @ Test
105+ @ Disabled
106+ void createNewKeystoreFile () throws CipherException , IOException {
107+ final String filePath = "C:\\ Ethereum\\ keystore" ;
108+ final File file = new File (filePath );
109+ final String password = "123456789" ;
110+ final String privateKey = "6871412854632d2ccd9c99901f5a0a3d838b31dbc6bfecae5f2382d6b7658bbf" ;
111+ ECKeyPair pair = ECKeyPair .create (new BigInteger (privateKey , 16 ));
112+ WalletUtils .generateWalletFile (password , pair , file , false );
113+ }
114+
115+ @ Test
116+ @ Disabled
117+ void testBlockNumbers () throws IOException {
118+ LocalDateTime from = LocalDateTime .of (2019 , 12 , 27 , 10 , 50 );
119+ LocalDateTime to = LocalDateTime .of (2019 , 12 , 27 , 10 , 56 );
120+ long fromBlockNumber = this .adapter .getBlockAfterIsoDate (from );
121+ long toBlockNumber = this .adapter .getBlockAfterIsoDate (to ) - 1 ;
122+ // sanity check
123+ Assertions .assertTrue ((toBlockNumber - fromBlockNumber ) * 12 < Duration .between (from , to ).getSeconds () * 2 );
124+ log .info ("From: {} to: {}" , fromBlockNumber , toBlockNumber );
125+ }
126+
127+ @ Test
128+ @ Disabled
129+ void testExtremeBlockNumbers () throws IOException {
130+ LocalDateTime from = LocalDateTime .of (2001 , 12 , 27 , 10 , 50 );
131+ LocalDateTime to = LocalDateTime .of (2029 , 12 , 27 , 10 , 56 );
132+ long fromBlockNumber = this .adapter .getBlockAfterIsoDate (from );
133+ long toBlockNumber = this .adapter .getBlockAfterIsoDate (to );
134+ // sanity check
135+ Assertions .assertEquals (0 , fromBlockNumber );
136+ Assertions .assertEquals (Long .MAX_VALUE , toBlockNumber );
137+ log .info ("From: {} to: {}" , fromBlockNumber , toBlockNumber );
138+ }
139+
140+ Permissions deployContract () throws ExecutionException , InterruptedException , IOException {
141+ Permissions contract = Permissions .deploy (this .adapter .getWeb3j (), this .adapter .getCredentials (),
142+ new DefaultGasProvider ()).sendAsync ().get ();
143+ Assertions .assertTrue (contract .isValid ());
144+
145+ return contract ;
146+ }
147+
148+ private EthereumAdapter getAdapter () {
149+ //String nodeUrl = "http://localhost:7545/";
150+ String nodeUrl = "https://rinkeby.infura.io/v3/cafcfb3fc02f4322be11087aad15989c" ;
151+
152+ String keystorePath = "/account.json" ;
153+ String keystorePassword = "123456789" ;
154+ double adversaryVotingRatio = 0.2 ;
155+ int pollingTimeSeconds = 2 ;
156+ EthereumAdapter ethereumAdapter = new EthereumAdapter (nodeUrl , pollingTimeSeconds );
157+ final PoWConfidenceCalculator cCalc = new PoWConfidenceCalculator ();
158+ cCalc .setAdversaryRatio (adversaryVotingRatio );
159+ try {
160+ ethereumAdapter .setCredentials (keystorePassword , keystorePath );
161+ } catch (IOException | CipherException e ) {
162+ e .printStackTrace ();
163+ }
164+ ethereumAdapter .setConfidenceCalculator (cCalc );
165+ return ethereumAdapter ;
166+ }
167+ }
0 commit comments