使用Java與以太坊智慧合約互動

買賣虛擬貨幣
在本教程中,您將學習如何使用Web3j Java庫部署智慧合約,以及如何與智慧合約的功能進行互動。作為先決條件,您應該熟悉帳戶管理和智慧合約java wrapper生成,如本系列前一篇文章中所述。為了保持連續性,我們將部署相同的DocumentRegistry智慧合約。區塊鏈研究實驗室|從您的智慧合同生成Java封裝器。DocumentRegistry.solpragma solidity ^0.5.6;/***  @dev Smart Contract resposible to notarize documents on the Ethereum Blockchain
*/contract DocumentRegistry {    struct Document {        address signer; // Notary        uint date; // Date of notarization        string hash; // Document Hash
    }    /**     *  @dev Storage space used to record all documents notarized with metadata     */    mapping(bytes32 => Document) registry;    /**
     *  @dev Notarize a document identified by the hash of the document hash, the sender and date in the registry     *  @dev Emit an event Notarized in case of success     *  @param _documentHash Document hash     */    function notarizeDocument(string calldata _documentHash) external returns (bool) {        bytes32 id = keccak256(abi.encodePacked(_documentHash));
        registry[id].signer = msg.sender;        registry[id].date = now;        registry[id].hash = _documentHash;        emit Notarized(msg.sender, _documentHash);        return true;    }
    /**     *  @dev Verify a document identified by its has was noterized in the registry previsouly.     *  @param _documentHash Document hash     *  @return bool if document was noterized previsouly in the registry     */    function isNotarized(string calldata _documentHash) external view returns (bool) {
        return registry[keccak256(abi.encodePacked(_documentHash))].signer != address(0);    }    /**     *  @dev Definition of the event triggered when a document is successfully notarized in the registry     */    event Notarized(address indexed _signer, string _documentHash);
}Mining與Gas的簡介Mining與以太坊網路的任何更新EVM狀態的互動必須由廣播到區塊鏈的交易觸發。一些示例互動包括將以太傳送到另一個帳戶、部署智慧合約和一些智慧合約函式呼叫。礦工是透過不斷嘗試計算複雜數學難題(一種稱為工作證明共識的機制)的答案來確保以太坊網路安全的實體。礦工的工作是(從mempool)收集一組掛起的事務,並建立一個包含這些事務的區塊。一旦一個事務包含在一個挖掘的區塊中,它就被認為是已執行的,並且任何相關的狀態更改都將被應用。
Gas以太幣,以太坊的原生加密貨幣,由交易傳送方支付給在一個區塊內包含交易的礦工,這是激勵礦工的方法之一。gas是以太坊網路中計算工作的一個單位,執行交易時支付的以太數量取決於消耗的gas量,以及gasPrice交易屬性,該屬性定義了傳送方每消耗一個gas單位將支付多少以太。重要的是要了解不同的交易將需要不同數量的gas,這取決於操作,每筆交易至少需要21,000個gas。還可以透過指定gaslimit屬性來定義事務傳送方為了執行事務而願意消耗的絕對最大gas量。部署部署永久存在的智慧合約的能力是以太坊的秘密!智慧合約是一段程式碼,其功能可由任何相關方執行。它們在網路中以位元組碼的形式存在,但通常使用Solidity或Vyper等語言編寫,然後進行編碼和部署。
到目前為止,部署DocumentRegistry智慧合約的最簡單方法是使用由Web3j生成的wrapper。此wrapper提供智慧合約的本機java類表示,提供了兩種(非棄用的)deploy方法,可用於將程式碼部署到以太坊網路:public static RemoteCall<DocumentRegistry> deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider)public static RemoteCall<DocumentRegistry> deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider)後者允許指定TransactionManager; 控制Web3j如何連線到以太坊客戶端的物件。我們很高興在此示例中使用預設的RawTransactionManager,因此我們將使用前一種方法,該方法將錢包憑據作為引數。我們還必須建立一個ContractGasProvider,它為交易提供gas價格和gas限制; 間接指定合同在Ether中部署的成本。
DocumentRegistry部署程式碼//Create credentials from private keyCredentials creds = Credentials.create("0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63");DocumentRegistry registryContract = DocumentRegistry.deploy(web3j, creds, new DefaultGasProvider()).send();
String contractAddress = registryContract.getContractAddress();deploy方法返回RemoteCall物件。在RemoteCall上同時呼叫send()會將智慧合約部署到以太坊網路,並返回與此部署程式碼連結的DocumentRegistry例項。每個部署的智慧合約都有一個與之關聯的唯一以太坊地址,並且可以透過在部署後呼叫合同包裝器上的getContractAddress()方法來訪問此地址。在此片段中,憑據由硬編碼的私鑰構成(對於地址0xfe3b557e8fb62b89f4916b721be55ceb828dbd73)。這適用於測試和演示目的,但生產實現永遠不應對私鑰進行硬編碼,因為攻擊者將能夠控制您的帳戶。解決此問題的一種方法是將金鑰設定為伺服器上的環境變數,並將其載入到程式碼中。在此示例中使用提供的DefaultGasProvider,它將gas價格和限制設定為硬編碼值,但可以透過實現以下介面來構建自定義版本:public interface ContractGasProvider {    BigInteger getGasPrice(String contractFunc);
    @Deprecated    BigInteger getGasPrice();    BigInteger getGasLimit(String contractFunc);    @Deprecated    BigInteger getGasLimit();}
為已經部署的合約建立wrapper例項通常情況下,您要與之互動的智慧合約將已部署到以太坊網路。在這種情況下,可以使用靜態載入(..)方法:public static DocumentRegistry load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider)public static DocumentRegistry load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider)
例如,如果我們的DocumentRegistry部署地址為0x10c7dc2b84b6c8e6df5a749655830e70adca3a2b,我們可以獲得已部署合同的java wrapper,如下所示://Create credentials from private keyCredentials creds = Credentials.create("0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63");DocumentRegistry registryContract = DocumentRegistry.load(web3j, creds, new DefaultGasProvider());

呼叫智慧合約功能


交易與呼叫根據函式的行為,可以透過兩種不同的方式呼叫智慧合約函式。交易要呼叫可能更改合同狀態(新增/更新/刪除值)的智慧合同功能,必須將事務廣播到以太坊網路。函式呼叫細節(如函式名和引數值)以眾所周知的格式編碼在事務的資料欄位中,與常規的ether值事務非常相似,呼叫將消耗氣體。
礦工必須選擇將事務包含在區塊中,以便進行函式呼叫,因此事務執行本質上是非同步的。廣播事務後,將返回一個唯一的雜湊,該雜湊隨後可用於從以太坊客戶端請求事務回執(一旦它包含在一個區塊中)。呼叫您服務所連線的以太坊客戶機的本地呼叫,不會向更廣泛的以太坊網路廣播任何內容。因此合約呼叫可以自由執行;他們不消耗任何gas。但是呼叫操作是隻讀的,這意味著在智慧合約函式中發生的任何狀態更改都不會持久化,並在執行後回滾。不涉及挖掘,因此執行是同步的。使用合約wrapper與部署一樣,使用Web3j生成的合約wrapper呼叫函式是迄今為止最簡單的方法。棘手的資料編碼在封面下為您封裝和處理。生成一個對應於您的智慧合約中的每個函式的Java方法。web3j根據函式的關鍵字,在wrapper生成時確定是否應該透過事務或呼叫自動呼叫函式。例如,包含view或pure關鍵字的函式定義將透過呼叫執行,否則它假定將發生一些潛在的狀態更改,並使用事務方法。
呼叫公證檔案(..)在我們的documentregistry示例smart contract中,公證文件(..)功能將文件詳細資訊儲存在smart contract狀態中,因此應透過非同步事務觸發。生成的函式簽名是:public RemoteCall<TransactionReceipt> notarizeDocument(String _documentHash)有趣的是,即使在後臺,事務也會非同步地廣播到網路幷包含在一個塊中,web3j代表您處理事務接收輪詢,因此該方法返回的遠端呼叫實際上是同步的,並且會一直阻塞到事務如已開採,隨後返回交易憑證。如果您的應用程式中不需要這種行為,您將不得不在不借助wrapper的情況下手動傳送事務,或者在其他執行緒上進行遠端呼叫。因此,使用wrapper呼叫notarizeDocument函式非常簡單,如下所示:DocumentRegistry documentRegistry = deployDocumentRegistryContract();
TransactionReceipt receipt = documentRegistry.notarizeDocument(        "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco").send();String txHash = receipt.getTransactionHash();如果事務失敗,則丟擲TransactionException。呼叫isNotarized(..)由於此函式被標記為view函式,因此表示它是隻讀的,因此可以在本地呼叫。生成的方法簽名是:
public RemoteCall<Boolean> isNotarized(String _documentHash)這種方法與notarizeDocument(..)方法非常相似,只有一個主要區別; 返回的RemoteCall是布林型別而不是TransactionReceipt。這是因為沒有傳送事務,而是同步返回智慧合約函式的返回值(在這種情況下為bool,轉換為布林值)。手動交易傳送如果出於某種原因,不希望使用智慧合約wrapper,web3j提供了許多助手類來簡化廣播函式呼叫事務的過程,例如編碼事務的資料欄位和簽名過程。手動交易傳送程式碼Function function = new Function("notarizeDocument",
                Arrays.asList(new Utf8String("QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco")), Collections.emptyList());//Encode function values in transaction data formatString txData = FunctionEncoder.encode(function);TransactionManager txManager = new FastRawTransactionManager(web3j, 
creds);String txHash = txManager.sendTransaction(DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT,                documentRegistry.getContractAddress(), txData, BigInteger.ZERO).getTransactionHash();· 首先建立一個Function物件。這定義了notarizeDocument函式呼叫,幷包含函式名稱,輸入引數列表(Web3j提供了所有可靠智慧合約型別的java等價物),以及返回型別列表(在我們的例子中為空)。
· 接下來,FunctionEncoder用於將函式呼叫定義編碼為事務資料欄位格式。實際編碼超出了本文的範圍,但如果感興趣,可以在此處找到詳細資訊。· 構建了一個TransactionManager,它將用於構建和簽署事務,並廣播到以太坊網路。在這種情況下,我們使用FastRawTransactionManager,它支援每個塊的多個事務,並將Web3j和Credentials物件作為引數。· 一旦我們有了事務管理器和編碼資料,呼叫notarizeDocument函式只需要呼叫事務管理器的sendTransaction方法。在幕後,這將構建一個事務物件,並使用憑據中定義的私鑰對其進行簽名,然後透過連線的客戶端將事務廣播到以太坊網路。雖然GasProvider的工作是在wrapper中設定氣體值,但我們使用此方法手動指定它們。我們在此示例中使用了預設值,但您可以根據需要更改這些值。由於智慧合約函式可以在呼叫期間接收以太(可支付函式),因此最後一個引數可用於指定應從傳送方帳戶傳送到的傳送方帳戶的乙太網(最小面額,wei)的數量。聰明的合同。在我們的情況下不應傳輸以太,因此該值設定為零。您可能已經注意到上面程式碼中的sendTransaction方法返回事務雜湊,而不是事務接收。 這是因為本指南前面已提到的事務處理的非同步性質。 幸運的是,web3j還提供了一種簡單的方法來輪詢網路,並等待一個礦工(TransactionReceiptProcessor)將事務包含在一個塊中:TransactionReceiptProcessor receiptProcessor =                new PollingTransactionReceiptProcessor(web3j, 
TransactionManager.DEFAULT_POLLING_FREQUENCY,           TransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH);TransactionReceipt txReceipt = receiptProcessor.waitForTransactionReceipt(txHash);總結在本指南中,您已經學會了如何在Java中執行與Ethunm BaseCu鏈的一些最常見的互動,即部署智慧合約,然後透過事務和呼叫來呼叫該合約上的函式。使用生成的智慧合同Java wrapper是迄今為止執行這些任務最簡單的方法,但如果需要更多粒度,則還有其他選項。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;