diff --git a/src/main/java/conflux/web3j/Account.java b/src/main/java/conflux/web3j/Account.java index 20c92ee..860ec5c 100644 --- a/src/main/java/conflux/web3j/Account.java +++ b/src/main/java/conflux/web3j/Account.java @@ -8,31 +8,47 @@ import org.web3j.abi.FunctionEncoder; import org.web3j.abi.datatypes.Function; import org.web3j.abi.datatypes.Type; +import org.web3j.crypto.Credentials; import org.web3j.crypto.RawTransaction; public class Account { private Cfx cfx; private AccountManager am; + private Credentials credentials; private String address; private BigInteger gasPrice = CfxUnit.DEFAULT_GAS_PRICE; private BigInteger nonce; - public Account(Cfx cfx, AccountManager am, String address, String password) throws Exception { - this(cfx, am, address, password, Duration.ZERO); + private Account(Cfx cfx, String address) { + this.cfx = cfx; + this.address = address; + this.nonce = cfx.getTransactionCount(address).sendAndGet(); } - public Account(Cfx cfx, AccountManager am, String address, String password, Duration unlockTimeout) throws Exception { + public static Account unlock(Cfx cfx, AccountManager am, String address, String password) throws Exception { + return unlock(cfx, am, address, password, Duration.ZERO); + } + + public static Account unlock(Cfx cfx, AccountManager am, String address, String password, Duration unlockTimeout) throws Exception { if (!am.unlock(address, password, unlockTimeout)) { throw new Exception("account not found in keystore"); } - this.cfx = cfx; - this.am = am; - this.address = address; + Account account = new Account(cfx, address); + account.am = am; - this.nonce = cfx.getTransactionCount(address).sendAndGet(); + return account; + } + + public static Account create(Cfx cfx, String privateKey) { + Credentials credentials = Credentials.create(privateKey); + + Account account = new Account(cfx, credentials.getAddress()); + account.credentials = credentials; + + return account; } public BigInteger getNonce() { @@ -49,7 +65,9 @@ public Account withGasPrice(BigInteger gasPrice) { } public String send(RawTransaction tx) throws Exception { - String signedTx = this.am.signTransaction(tx, this.address); + String signedTx = this.credentials == null + ? this.am.signTransaction(tx, this.address) + : AccountManager.signTransaction(tx, this.credentials); String txHash = this.cfx.sendRawTransaction(signedTx).sendAndGet(); if (txHash == null || txHash.isEmpty()) { diff --git a/src/main/java/conflux/web3j/AccountManager.java b/src/main/java/conflux/web3j/AccountManager.java index 66112e4..1930943 100644 --- a/src/main/java/conflux/web3j/AccountManager.java +++ b/src/main/java/conflux/web3j/AccountManager.java @@ -247,10 +247,10 @@ public boolean unlock(String address, String password, Duration... timeout) thro UnlockedItem item; - if (timeout == null || timeout.length == 0 || timeout[0].isNegative() || timeout[0].isZero()) { - item = new UnlockedItem(credentials, Optional.empty()); - } else { + if (timeout != null && timeout.length > 0 && timeout[0] != null && timeout[0].compareTo(Duration.ZERO) > 0) { item = new UnlockedItem(credentials, Optional.of(timeout[0])); + } else { + item = new UnlockedItem(credentials, Optional.empty()); } this.unlocked.put(address, item); @@ -278,7 +278,10 @@ public boolean lock(String address) { */ public String signTransaction(RawTransaction tx, String address, String... password) throws Exception { Credentials credentials = this.getCredentials(address, password); - + return signTransaction(tx, credentials); + } + + public static String signTransaction(RawTransaction tx, Credentials credentials) { byte[] encodedTx = TransactionEncoder.encode(tx); Sign.SignatureData signature = Sign.signMessage(encodedTx, credentials.getEcKeyPair()); List fields = TransactionEncoder.asRlpValues(tx, signature); @@ -292,8 +295,9 @@ public String signTransaction(RawTransaction tx, String address, String... passw } private Credentials getCredentials(String address, String... password) throws IOException, CipherException { - if (password == null || password.length == 0) { - UnlockedItem item = this.unlocked.get(address); + UnlockedItem item = this.unlocked.get(address); + + if (password == null || password.length == 0 || password[0] == null || password[0].isEmpty()) { if (item == null) { throw new IllegalArgumentException("password not specified for locked account"); } @@ -305,6 +309,14 @@ private Credentials getCredentials(String address, String... password) throws IO return item.getCredentials(); } else { + if (item != null) { + if (!item.expired()) { + return item.getCredentials(); + } + + this.unlocked.remove(address); + } + List files = Files.list(Paths.get(this.dir)) .filter(path -> this.parseAddressFromFilename(path.getFileName().toString()).equalsIgnoreCase(address)) .collect(Collectors.toList()); @@ -319,7 +331,10 @@ private Credentials getCredentials(String address, String... password) throws IO public String signMessage(byte[] message, boolean needToHash, String address, String... password) throws Exception { Credentials credentials = this.getCredentials(address, password); - + return signMessage(message, needToHash, credentials); + } + + public static String signMessage(byte[] message, boolean needToHash, Credentials credentials) { Sign.SignatureData data = Sign.signMessage(message, credentials.getEcKeyPair(), needToHash); byte[] rsv = new byte[data.getR().length + data.getS().length + data.getV().length];