處理交易請求時出錯:發送方沒有足夠的資金來發送 tx
在一個 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 會在後台實例化 aRawTransactionManager
,它將在將交易發送到節點之前簽署交易(使用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"));