Web3j

處理交易請求時出錯:發送方沒有足夠的資金來發送 tx

  • January 30, 2019

在一個 Java 項目中,我正在測試 web3j 庫。我有一種方法可以為區塊鏈生成一個新帳戶

public String url = "http://localhost:7545/";
public Admin admin = Admin.build(new HttpService(url));

NewAccountIdentifier newAccountIdentifier = admin.personalNewAccount(key).send();
String address = newAccountIdentifier.getAccountId();

       if (newAccountIdentifier.hasError()) {
           Error error = newAccountIdentifier.getError();
           int code = error.getCode();
           String message = error.getMessage();
           throw new IllegalStateException(code + ": " + message);
       }

當我生成使用者時,我將部署的合約從 Remix IDE 實例化到 Ganache 區塊鏈。

UsersContract userContract = UsersContract.load("0xc85e6e4b979d05a9b5adbac3e0e7d68b632460d1", admin, credentials, new BigInteger("240000"), new BigInteger("2400000"));

TransactionReceipt transactionReceipt = userContract.addUser(address).send();

生成帳戶(出現在重新混合帳戶欄位中)並且 Java 程式碼到達已部署的契約。因為我有以下錯誤:

java.lang.RuntimeException:處理交易請求時出錯:發送方沒有足夠的資金來發送 tx。前期費用為:576000000000 發件人賬戶只有:0

所以我創建了一個方法,從第一個 ganache 賬戶(100 eth)給新賬戶一定數量的乙太幣。該方法工作正常

在此處輸入圖像描述

所以我遵循的流程是:

  • 建立新帳戶
  • 將帶有乙太幣的預生成帳戶中的 eth 發送到新帳戶
  • 使用地址載入已部署的合約
  • 當這一行執行時 (TransactionReceipt transactionReceipt = userContract.addUser(address).send();) 我得到了異常

主要問題是我無法理解發生了什麼。首先我在想新使用者沒有乙太幣所以不能完成交易。我製作了一種提供乙太的方法,但問題仍然存在。所以現在我被封鎖了。如果我在沒有 web3j 的情況下進行交易並且我從他的 Remix IDE 呼叫交易完成並且氣體成本是 70853,而不是返回 Java 異常的 576….數字

我的另一個問題是,當我載入契約時,我載入的憑據是新的帳戶憑據。總是載入設置為預設值的帳戶更有意義(預設我是指部署契約的帳戶,因為契約內部出現了 onlyOwner 修飾符),或者載入新地址的憑證更有意義?

有什麼幫助嗎?

通過節點將交易發送到智能合約有不同的方式:

  • (1) 客戶用他的賬戶(私鑰)簽署一筆交易並將其發送給節點。然後節點僅將其廣播到網路。 交易費用由客戶支付。
  • (2) 客戶發送明文交易(無簽名)並要求節點用該節點管理的賬戶之一簽署和廣播該交易。personal unlocked account這就是應該用於個人使用或測試 的所有概念。交易費用由節點支付。

通過這樣做(如下),您基本上可以直接在節點上創建一個帳戶 (2)

NewAccountIdentifier newAccountIdentifier = admin.personalNewAccount(key).send();
String address = newAccountIdentifier.getAccountId();

如果您只想在客戶端(java 程序)上創建和管理帳戶,則必須這樣做:

ECKeyPair keyPair = Keys.createEcKeyPair(); 
Credentials credentials = Credentials.create(privateKey);

在 web3j 中,您有TransactionManager負責執行事務的概念,並且您有不同類型的 TransactionManager:

  • RawTransactionManager可以簽署和發送交易 (1)
  • ReadonlyTransactionManager只能讀取數據(無事務)
  • ClientTransactionManager只能向節點發送明確的交易並讓節點簽名(2)

當您像以前一樣載入契約時UsersContract userContract = UsersContract.load(address, admin, credential, ...),Web3J 會在後台實例化 a RawTransactionManager,它將在將交易發送到節點之前簽署交易(使用credentials- 私鑰)。

UsersContract userContract = UsersContract.load("0xc85e6e4b979d05a9b5adbac3e0e7d68b632460d1", admin, credentials, new BigInteger("240000"), new BigInteger("2400000"));

但在你的情況下,你實際上需要 a ClientTransactionManager,所以你可以直接將它傳遞給這樣的UsersContract.load(...)方法

ClientTransactionManager transactionManager = new ClientTransactionManager(web3j, newAccountIdentifier.getAccountId());
UsersContract userContract = UsersContract.load("0xc85e6e4b979d05a9b5adbac3e0e7d68b632460d1", admin, transactionManager, new BigInteger("240000"), new BigInteger("2400000"));

引用自:https://ethereum.stackexchange.com/questions/66367