Skip to content

Commit

Permalink
Add eth_sendTransaction (#835)
Browse files Browse the repository at this point in the history
* Add eth_signTransaction

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

---------

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
Co-authored-by: Jason Frame <jasonwframe@gmail.com>
  • Loading branch information
3 people authored Jul 18, 2023
1 parent 6b3747e commit 02e9c55
Show file tree
Hide file tree
Showing 76 changed files with 5,827 additions and 114 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
- Azure bulk mode support for loading multiline (`\n` delimited, up to 200) keys per secret.
- Hashicorp connection properties can now override http protocol to HTTP/1.1 from the default of HTTP/2. [#817](https://github.com/ConsenSys/web3signer/pull/817)
- Add --key-config-path as preferred alias to --key-store-path [#826](https://github.com/Consensys/web3signer/pull/826)
- Add eth_SignTransaction RPC method under the eth1 subcommand [#822](https://github.com/ConsenSys/web3signer/pull/822)
- Add eth_signTransaction RPC method under the eth1 subcommand [#822](https://github.com/ConsenSys/web3signer/pull/822)
- Add eth_sendTransaction RPC method under the eth1 subcommand [#835](https://github.com/Consensys/web3signer/pull/835)


### Bugs fixed
- Support long name aliases in environment variables and YAML configuration [#825](https://github.com/Consensys/web3signer/pull/825)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
*/
package tech.pegasys.web3signer.dsl;

import java.math.BigInteger;

public class Account {

private final String address;
private BigInteger nonce = BigInteger.ZERO;

public Account(final String address) {
this.address = address;
Expand All @@ -23,4 +26,16 @@ public Account(final String address) {
public String address() {
return address;
}

public BigInteger nextNonce() {
return nonce;
}

public BigInteger nextNonceAndIncrement() {

final BigInteger next = nonce;
nonce = nonce.add(BigInteger.ONE);

return next;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,26 @@

public class Accounts {

/** Private key: 8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63 */
private static final String GENESIS_ACCOUNT_ONE_PUBLIC_KEY =
"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73";

public static final String GENESIS_ACCOUNT_ONE_PASSWORD = "pass";

private final Account benefactor;
private final Eth eth;

public Accounts(final Eth eth) {
this.eth = eth;
this.benefactor = new Account(GENESIS_ACCOUNT_ONE_PUBLIC_KEY);
}

public Account richBenefactor() {
return benefactor;
}

public BigInteger balance(final Account account) {
return balance(account.address());
}

public BigInteger balance(final String address) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.web3signer.dsl;

import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.web3signer.dsl.utils.ExceptionUtils.failOnIOException;
import static tech.pegasys.web3signer.dsl.utils.WaitUtils.waitFor;

import tech.pegasys.web3signer.core.service.jsonrpc.response.JsonRpcErrorResponse;
import tech.pegasys.web3signer.dsl.signer.SignerResponse;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.awaitility.core.ConditionTimeoutException;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

public abstract class Contracts<T> {

private static final Logger LOG = LogManager.getLogger();

public static final BigInteger GAS_PRICE = BigInteger.valueOf(1000);
public static final BigInteger GAS_LIMIT = BigInteger.valueOf(3000000);

public abstract String sendTransaction(T smartContract) throws IOException;

public abstract SignerResponse<JsonRpcErrorResponse> sendTransactionExpectsError(T smartContract)
throws IOException;

public abstract Optional<? extends TransactionReceipt> getTransactionReceipt(final String hash)
throws IOException;

public String submit(final T smartContract) {
return failOnIOException(() -> sendTransaction(smartContract));
}

public void awaitBlockContaining(final String hash) {
try {
waitFor(() -> assertThat(getTransactionReceipt(hash).isPresent()).isTrue());
} catch (final ConditionTimeoutException e) {
LOG.error("Timed out waiting for a block containing the transaction receipt hash: " + hash);
}
}

public String address(final String hash) {
return failOnIOException(
() -> {
final TransactionReceipt receipt =
getTransactionReceipt(hash)
.orElseThrow(() -> new RuntimeException("No receipt found for hash: " + hash));
assertThat(receipt.getContractAddress()).isNotEmpty();
return receipt.getContractAddress();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@
*/
package tech.pegasys.web3signer.dsl;

import static org.assertj.core.api.Assertions.assertThat;

import tech.pegasys.web3signer.core.service.jsonrpc.response.JsonRpcErrorResponse;
import tech.pegasys.web3signer.dsl.signer.SignerResponse;

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;

import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

public class Eth {

Expand All @@ -27,11 +36,49 @@ public Eth(final Web3j jsonRpc) {
this.jsonRpc = jsonRpc;
}

public String sendTransaction(final Transaction transaction) throws IOException {
final EthSendTransaction response = jsonRpc.ethSendTransaction(transaction).send();

assertThat(response.getTransactionHash()).isNotEmpty();
assertThat(response.getError()).isNull();

return response.getTransactionHash();
}

public SignerResponse<JsonRpcErrorResponse> sendTransactionExpectsError(
final Transaction transaction) throws IOException {
final EthSendTransaction response = jsonRpc.ethSendTransaction(transaction).send();
assertThat(response.hasError()).isTrue();
return SignerResponse.fromWeb3jErrorResponse(response);
}

public BigInteger getTransactionCount(final String address) throws IOException {
return jsonRpc
.ethGetTransactionCount(address, DefaultBlockParameterName.LATEST)
.send()
.getTransactionCount();
}

public Optional<TransactionReceipt> getTransactionReceipt(final String hash) throws IOException {
return jsonRpc.ethGetTransactionReceipt(hash).send().getTransactionReceipt();
}

public List<String> getAccounts() throws IOException {
return jsonRpc.ethAccounts().send().getAccounts();
}

public String getCode(final String address) throws IOException {
return jsonRpc.ethGetCode(address, DefaultBlockParameterName.LATEST).send().getResult();
}

public BigInteger getBalance(final String account) throws IOException {
return jsonRpc.ethGetBalance(account, DefaultBlockParameterName.LATEST).send().getBalance();
}

public String call(final Transaction contractViewOperation) throws IOException {
return jsonRpc
.ethCall(contractViewOperation, DefaultBlockParameterName.LATEST)
.send()
.getValue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.web3signer.dsl;

import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.web3signer.dsl.utils.ExceptionUtils.failOnIOException;

import tech.pegasys.web3signer.core.service.jsonrpc.response.JsonRpcErrorResponse;
import tech.pegasys.web3signer.dsl.signer.SignerResponse;

import java.io.IOException;
import java.util.Optional;

import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

public class PublicContracts extends Contracts<Transaction> {

private final Eth eth;

public PublicContracts(final Eth eth) {
this.eth = eth;
}

@Override
public String sendTransaction(final Transaction smartContract) throws IOException {
return eth.sendTransaction(smartContract);
}

@Override
public SignerResponse<JsonRpcErrorResponse> sendTransactionExpectsError(
final Transaction smartContract) throws IOException {
return eth.sendTransactionExpectsError(smartContract);
}

@Override
public Optional<TransactionReceipt> getTransactionReceipt(final String hash) throws IOException {
return eth.getTransactionReceipt(hash);
}

public String code(final String address) {
return failOnIOException(
() -> {
final String code = eth.getCode(address);
assertThat(code).isNotEmpty();
return code;
});
}

public String call(final Transaction contractViewOperation) {
return failOnIOException(() -> eth.call(contractViewOperation));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.web3signer.dsl;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static tech.pegasys.web3signer.dsl.utils.ExceptionUtils.failOnIOException;
import static tech.pegasys.web3signer.dsl.utils.WaitUtils.waitFor;

import tech.pegasys.web3signer.core.service.jsonrpc.response.JsonRpcErrorResponse;
import tech.pegasys.web3signer.dsl.signer.SignerResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.awaitility.core.ConditionTimeoutException;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.exceptions.ClientConnectionException;

public class Transactions {

private static final Logger LOG = LogManager.getLogger();

private final Eth eth;

public Transactions(final Eth eth) {
this.eth = eth;
}

public String submit(final Transaction transaction) {
return failOnIOException(() -> eth.sendTransaction(transaction));
}

public SignerResponse<JsonRpcErrorResponse> submitExceptional(final Transaction transaction) {
try {
return failOnIOException(() -> eth.sendTransactionExpectsError(transaction));
} catch (final ClientConnectionException e) {
LOG.info("ClientConnectionException with message: " + e.getMessage());
return SignerResponse.fromError(e);
}
}

public void awaitBlockContaining(final String hash) {
try {
waitFor(() -> assertThat(eth.getTransactionReceipt(hash).isPresent()).isTrue());
} catch (final ConditionTimeoutException e) {
LOG.error("Timed out waiting for a block containing the transaction receipt hash: " + hash);
throw new RuntimeException("No receipt found for hash: " + hash);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import tech.pegasys.web3signer.dsl.Accounts;
import tech.pegasys.web3signer.dsl.Eth;
import tech.pegasys.web3signer.dsl.PublicContracts;
import tech.pegasys.web3signer.dsl.Transactions;

import java.io.IOException;
import java.io.StringReader;
Expand Down Expand Up @@ -52,12 +54,16 @@ public class BesuNode {
private static final BigInteger SPURIOUS_DRAGON_HARD_FORK_BLOCK = BigInteger.valueOf(1);

private final BesuNodeConfig besuNodeConfig;

private final String[] args;

private final Map<String, String> environment;
private final Properties portsProperties = new Properties();
private Accounts accounts;
private Future<ProcessResult> besuProcess;
private Transactions transactions;
private Web3j jsonRpc;
private PublicContracts publicContracts;
private BesuNodePorts besuNodePorts;

BesuNode(final BesuNodeConfig besuNodeConfig, String[] args, Map<String, String> environment) {
Expand Down Expand Up @@ -130,6 +136,8 @@ public void awaitStartupCompletion() {
final Eth eth = new Eth(jsonRpc);

accounts = new Accounts(eth);
publicContracts = new PublicContracts(eth);
transactions = new Transactions(eth);
}

public BesuNodePorts ports() {
Expand Down Expand Up @@ -159,4 +167,12 @@ private void loadPortsFile() {
throw new RuntimeException("Error reading Besu ports file", e);
}
}

public PublicContracts publicContracts() {
return publicContracts;
}

public Transactions transactions() {
return transactions;
}
}
Loading

0 comments on commit 02e9c55

Please sign in to comment.