测试合约
以下智能合约是上一指南中multiply
合约的更新版本:
contract test { int _multiplier; event Multiplied(int indexed a, address indexed sender, int result ); function test(int multiplier) { _multiplier = multiplier; } function multiply(int a) returns (int r) { r = a * _multiplier; Multiplied(a, msg.sender, r); return r; } }
智能合约现在是一个Multiplied
事件。该事件将在日志中存储原始参数包括a
,sender
的地址和结果result
。参数a
和sender
的地址都被编入索引,因此我们可以使用主题topic
为这两个创建特定的过滤器filter
。
部署合约
我们可以按如下方式部署合约:
var senderAddress = "0x12890d2cce102216644c59daE5baed380d84830c"; var password = "password"; var abi = @"[{'constant':false,'inputs':[{'name':'a','type':'int256'}],'name':'multiply','outputs':[{'name':'r','type':'int256'}],'type':'function'},{'inputs':[{'name':'multiplier','type':'int256'}],'type':'constructor'},{'anonymous':false,'inputs':[{'indexed':true,'name':'a','type':'int256'},{'indexed':true,'name':'sender','type':'address'},{'indexed':false,'name':'result','type':'int256'}],'name':'Multiplied','type':'event'}]"; var byteCode = "0x6060604052604051602080610104833981016040528080519060200190919050505b806000600050819055505b5060ca8061003a6000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480631df4f144146037576035565b005b604b60048080359060200190919050506061565b6040518082815260200191505060405180910390f35b60006000600050548202905080503373ffffffffffffffffffffffffffffffffffffffff16827f841774c8b4d8511a3974d7040b5bc3c603d304c926ad25d168dacd04e25c4bed836040518082815260200191505060405180910390a380905060c5565b91905056"; var multiplier = 7; var web3 = new Web3.Web3(); var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(senderAddress, password, new HexBigInteger(120)); Assert.True(unlockResult); var transactionHash = await web3.Eth.DeployContract.SendRequestAsync(abi, byteCode, senderAddress, new HexBigInteger(900000), multiplier); var receipt = await MineAndGetReceiptAsync(web3, transactionHash);
multiply乘法交易
这是在智能合约状态下执行的,或者我们正在执行操作(如乘法),调用不是通过区块链一致性验证的交易。
提交交易以在智能合约中执行功能操作不会返回结果,我们可以通过使用函数调用来检查智能合约的条件。
var contractAddress = receipt.ContractAddress; var contract = web3.Eth.GetContract(abi, contractAddress); var multiplyFunction = contract.GetFunction("multiply"); transactionHash = await multiplyFunction.SendTransactionAsync(senderAddress, 7); transactionHash = await multiplyFunction.SendTransactionAsync(senderAddress, 8); receipt = await MineAndGetReceiptAsync(web3, transactionHash);
使用部署交易的合同地址,我们可以创建合约对象的实例和函数“multiply”。
函数对象以与调用相同的方式简化提交交易。根据上面的例子,我们只需要包含“senderAddress”,其将与操作相关的gas及函数的参数操作一起缴费。
还可以选择指定gas或以太币值作为交易的一部分。
在示例中,我们提交了2个交易来执行7和8的乘法,并在我们的私有测试链上等待交易被挖掘。
事件,过滤器和主题
创建事件和过滤器
事件被定义为abi的一部分,类似于我们可以使用合约实例获取事件的函数。
var multiplyEvent = contract.GetEvent("Multiplied");
事件对象允许创建create以查询存储在日志中的信息。
我们可以创建查询所有事件日志的过滤器。
var filterAll = await multiplyEvent.CreateFilterAsync();
或者指定一个主题。
var filter7 = await multiplyEvent.CreateFilterAsync(7);
在上面的例子中,我们查询了参数为7的日志,因为这个输入参数被标记为索引,我们可以过滤该主题。
我们使用发件人地址作为过滤器,因为它也被标记为索引,但如果我们想要过滤该特定主题,我们将在创建过滤器时第二个参数。
var filterSender = await multiplyEvent.CreateFilterAsync(null, senderAddress);
DTO事件
事件数据传输对象将所有事件参数解码为传输对象,其方式与我们将Json对象反序列化的方式类似。
public class MultipliedEvent { [Parameter("int", "a", 1, true)] public int MultiplicationInput {get; set;} [Parameter("address", "sender", 2, true)] public string Sender {get; set;} [Parameter("int", "result", 3, false)] public int Result {get; set;} }
在上面的示例中,MultipliedEvent
属性已使用自定义参数属性mapped
到事件参数。
每个参数都指定原始类型,名称,顺序以及它是否被索引。我们可以看到地址的类型被解码为字符串,在我们的场景中,我们可以安全地将int256
解码为int32
,但如果不知道最终类型BigInteger
将是一个更好的选择。
查询事件和日志
使用我们已经创建的过滤器,我们可以查询日志和事件。
var log = await multiplyEvent.GetFilterChanges<MultipliedEvent>(filterAll); var log7 = await multiplyEvent.GetFilterChanges<MultipliedEvent>(filter7);
上面我们使用GetFilterChanges
,这可用于查询过滤符合我们条件的,已创建或自上次我们尝试获取更改以来的任何日志。
参数将用于使用GetAllChanges
的FilterInput
。
作者:编程狂魔
链接:https://www.jianshu.com/p/422a38565b20