使用Nethereum库的以太坊.NET开发示例

这是一篇文章的早期版本,旨在帮助那些对以太坊区块链平台有基本了解的开发人员,如果想学习如何使用Nethereum .NET库对Ethereum平台进行编程。

我以后会在这篇文章中添加更多内容,但就目前而言,正在使用它发布.NET 10+的系列C#示例,介绍如何使用Nethereum库执行针对以太坊区块链平台的最常见任务。

最常见任务列表包括以下内容:

  • 1.获取协议版本
  • 2.获取最大块数
  • 3.获取帐户余额
  • 4.发送以太
  • 5.等待交易收据
  • 6.在区块链中扫描块
  • 7.列出个人账户(及其余额)
  • 8.在区块链中扫描交易
  • 9.与现有(已部署)合同互动
  • 10.用事件和现有(已部署)合约交互
  • 11.获取所有活动更改
  • 12.获取合约金额历史

这里是c#的主文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Nethereum.Hex.HexTypes;
using Nethereum.Web3;

namespace MWH.MyNethereum.QuickRef
{
static public class TaskExamples
{
const int UNLOCK_TIMEOUT = 2 * 60; // 2 minutes (arbitrary)
const int SLEEP_TIME = 5 * 1000; // 5 seconds (arbitrary)
const int MAX_TIMEOUT = 2 * 60 * 1000; // 2 minutes (arbirtrary)

// These static public variables do not represent a recommended pattern
static public string LastProtocolVersion = "";
static public string LastTxHash = "";
static public Nethereum.RPC.Eth.DTOs.TransactionReceipt LastTxReceipt = null;
static public HexBigInteger LastMaxBlockNumber = new HexBigInteger(0);

static public async Task GetProtocolVersionExample(Web3 web3)
{
Console.WriteLine("GetProtocolVersionExample:");

var protocolVersion = await web3.Eth.ProtocolVersion.SendRequestAsync();
Console.WriteLine("protocolVersion:\t" + protocolVersion.ToString());
LastProtocolVersion = protocolVersion;
}

static public async Task GetMaxBlockExample(Web3 web3)
{
Console.WriteLine("GetMaxBlockExample:");

var maxBlockNumber = await web3.Eth.Blocks.GetBlockNumber.SendRequestAsync();
Console.WriteLine("maxBlockNumber:\t" + maxBlockNumber.Value.ToString());
LastMaxBlockNumber = maxBlockNumber;
}

static public async Task ScanBlocksExample(Web3 web3, ulong startBlockNumber, ulong endBlockNumber)
{
Console.WriteLine("ScanBlocksExample:");

long txTotalCount = 0;
for (ulong blockNumber = startBlockNumber; blockNumber <= endBlockNumber; blockNumber++)
{
var blockParameter = new Nethereum.RPC.Eth.DTOs.BlockParameter(blockNumber);
var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockParameter);
var trans = block.Transactions;
int txCount = trans.Length;
txTotalCount += txCount;
if (blockNumber % 1000 == 0) Console.Write(".");
if (blockNumber % 10000 == 0)
{
DateTime blockDateTime = Helpers.UnixTimeStampToDateTime((double)block.Timestamp.Value);
Console.WriteLine(blockNumber.ToString() + " " + txTotalCount.ToString() + " " + blockDateTime.ToString());
}
}
Console.WriteLine();
}

static public async Task ScanTxExample(Web3 web3, ulong startBlockNumber, ulong endBlockNumber)
{
Console.WriteLine("ScanTxExample:");

long txTotalCount = 0;
for (ulong blockNumber = startBlockNumber; blockNumber <= endBlockNumber; blockNumber++)
{
var blockParameter = new Nethereum.RPC.Eth.DTOs.BlockParameter(blockNumber);
var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockParameter);
var trans = block.Transactions;
int txCount = trans.Length;
txTotalCount += txCount;
foreach (var tx in trans)
{
try
{
var bn = tx.BlockNumber.Value;
var th = tx.TransactionHash;
var ti = tx.TransactionIndex.Value;

var rpt = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(th);
var status = rpt.Status.Value;

var nc = tx.Nonce.Value;
var from = tx.From;

Console.WriteLine(th.ToString() + " " + ti.ToString() + " " + from.ToString() + " " + status.ToString());

var to = tx.To;
if (to == null) to = "to:NULL";
var v = tx.Value.Value;
var g = tx.Gas.Value;
var gp = tx.GasPrice.Value;
Console.WriteLine(th.ToString() + " " + ti.ToString() + " " + nc.ToString() + " " + from.ToString() + " " + to.ToString() + " " + v.ToString() + " " + g.ToString() + " " + gp.ToString());
}
catch (Exception ex)
{
Console.WriteLine("ScanTxExample.Tx:\t" + ex.ToString());
if (ex.InnerException != null) Console.WriteLine("ScanTxExample.Tx:\t" + ex.InnerException.ToString());
}
}
Console.WriteLine();
}
}

static public async Task GetAccountBalanceExample(Web3 web3, string accountAddress)
{
Console.WriteLine("GetAccountBalanceExample:");

var balanceWei = await web3.Eth.GetBalance.SendRequestAsync(accountAddress);
var balanceEther = Web3.Convert.FromWei(balanceWei.Value);
Console.WriteLine("accountAddress:\t" + accountAddress.ToString());
Console.WriteLine("balanceEther:\t" + balanceEther.ToString());
}

static public async Task ListPersonalAccountsExample(Web3 web3)
{
Console.WriteLine("ListPersonalAccountsExample:");

var accounts = await web3.Personal.ListAccounts.SendRequestAsync();
foreach (var account in accounts)
{
var balanceWei = await web3.Eth.GetBalance.SendRequestAsync(account);
var balanceEther = Web3.Convert.FromWei(balanceWei.Value);
Console.WriteLine("account:\t" + account + " balanceEther:\t" + balanceEther.ToString());
}
}

static public async Task SendEtherExample(Web3 web3, string fromAddress, string fromPassword, string toAddress, long amountWei)
{
Console.WriteLine("SendEtherExample:");

var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(fromAddress, fromPassword, UNLOCK_TIMEOUT);
var sendTxHash = await web3.Eth.TransactionManager.SendTransactionAsync(fromAddress, toAddress, new HexBigInteger(amountWei));
Console.WriteLine("fromAddress:\t" + fromAddress.ToString());
Console.WriteLine("toAddress:\t" + toAddress.ToString());
Console.WriteLine("amountWei:\t" + amountWei.ToString());
Console.WriteLine("sendTxHash:\t" + sendTxHash.ToString());
LastTxHash = sendTxHash;
}

static public async Task WaitForTxReceiptExample(Web3 web3, string txHash)
{
Console.WriteLine("WaitForTxReceiptExample:");

int timeoutCount = 0;
var txReceipt = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash);
while (txReceipt == null && timeoutCount < MAX_TIMEOUT)
{
Console.WriteLine("Sleeping...");
Thread.Sleep(SLEEP_TIME);
txReceipt = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash);
timeoutCount += SLEEP_TIME;
}
Console.WriteLine("timeoutCount " + timeoutCount.ToString());
LastTxReceipt = txReceipt;
}

static public async Task InteractWithExistingContractExample(Web3 web3, string fromAddress, string fromPassword, string contractAddress, string contractAbi)
{
Console.WriteLine("InteractWithExistingContractExample:");

var contract = web3.Eth.GetContract(contractAbi, contractAddress);

var setMessageFunction = contract.GetFunction("setMsg");
var getMessageFunction = contract.GetFunction("getMsg");

string nowTimestamp = DateTime.UtcNow.ToString() + " UTC";
Console.WriteLine("now:\t" + nowTimestamp);

var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(fromAddress, fromPassword, UNLOCK_TIMEOUT);
var txHash1 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 1, "Hello World");
Console.WriteLine("txHash1:\t" + txHash1.ToString());
var txHash2 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 2, nowTimestamp);
Console.WriteLine("txHash2:\t" + txHash2.ToString());

var txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
int timeoutCount = 0;
while (txReceipt2 == null && timeoutCount < MAX_TIMEOUT)
{
Console.WriteLine("Sleeping...");
Thread.Sleep(SLEEP_TIME);
txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
timeoutCount += SLEEP_TIME;
}
Console.WriteLine("timeoutCount:\t" + timeoutCount.ToString());

var txReceipt3 = await setMessageFunction.SendTransactionAndWaitForReceiptAsync(fromAddress, new HexBigInteger(900000), null, null, 2, nowTimestamp + " Wait");
Console.WriteLine("txReceipt3:\t" + txReceipt3.TransactionHash.ToString());
Console.WriteLine("txReceipt3:\t" + txReceipt3.CumulativeGasUsed.Value.ToString());

var getResult1 = await getMessageFunction.CallAsync<string>(1);
Console.WriteLine("getResult1:\t" + getResult1.ToString());
var getResult2 = await getMessageFunction.CallAsync<string>(2);
Console.WriteLine("getResult2:\t" + getResult2.ToString());
}

static public async Task InteractWithExistingContractWithEventsExample(Web3 web3, string fromAddress, string fromPassword, string contractAddress, string contractAbi)
{
Console.WriteLine("InteractWithExistingContractWithEventsExample:");

var contract = web3.Eth.GetContract(contractAbi, contractAddress);

var setMessageFunction = contract.GetFunction("setMsg");
var getMessageFunction = contract.GetFunction("getMsg");
var multipliedEvent = contract.GetEvent("MultipliedEvent");
var newMessageEvent = contract.GetEvent("NewMessageEvent");

var filterAllMultipliedEvent = await multipliedEvent.CreateFilterAsync();
var filterAllNewMessageEvent = await newMessageEvent.CreateFilterAsync();

string nowTimestamp = DateTime.UtcNow.ToString() + " UTC";
Console.WriteLine("now:\t" + nowTimestamp);

var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(fromAddress, fromPassword, UNLOCK_TIMEOUT);
var txHash1 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 1, "Hello World");
Console.WriteLine("txHash1:\t" + txHash1.ToString());
var txHash2 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 2, nowTimestamp);
Console.WriteLine("txHash2:\t" + txHash2.ToString());

var txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
int timeoutCount = 0;
while (txReceipt2 == null && timeoutCount < MAX_TIMEOUT)
{
Console.WriteLine("Sleeping...");
Thread.Sleep(SLEEP_TIME);
txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
timeoutCount += SLEEP_TIME;
}
Console.WriteLine("timeoutCount:\t" + timeoutCount.ToString());

var txReceipt3 = await setMessageFunction.SendTransactionAndWaitForReceiptAsync(fromAddress, new HexBigInteger(900000), null, null, 2, nowTimestamp + " Wait");
Console.WriteLine("txReceipt3:\t" + txReceipt3.TransactionHash.ToString());
Console.WriteLine("txReceipt3:\t" + txReceipt3.CumulativeGasUsed.Value.ToString());

var getResult1 = await getMessageFunction.CallAsync<string>(1);
Console.WriteLine("getResult1:\t" + getResult1.ToString());
var getResult2 = await getMessageFunction.CallAsync<string>(2);
Console.WriteLine("getResult2:\t" + getResult2.ToString());

var logMultipliedEvents = await multipliedEvent.GetFilterChanges<FunctionOutputHelpers.MultipliedEventArgs>(filterAllMultipliedEvent);
foreach (var mea in logMultipliedEvents)
{
Console.WriteLine("multipliedEvent:\t" +
mea.Event.sender + " " + mea.Event.oldProduct.ToString() + " " + mea.Event.value.ToString() + " " + mea.Event.newProduct.ToString());
}

var logNewMessageEvents = await newMessageEvent.GetFilterChanges<FunctionOutputHelpers.NewMessageEventArgs>(filterAllNewMessageEvent);
foreach (var mea in logNewMessageEvents)
{
Console.WriteLine("newMessageEvent:\t" +
mea.Event.sender + " " + mea.Event.ind.ToString() + " " + mea.Event.msg.ToString());
}
}

static public async Task GetAllChangesExample(Web3 web3, string fromAddress, string fromPassword, string contractAddress, string contractAbi)
{
Console.WriteLine("GetAllChangesExample:");

var contract = web3.Eth.GetContract(contractAbi, contractAddress);
var newMessageEvent = contract.GetEvent("NewMessageEvent");
var filterAllNewMessageEvent = await newMessageEvent.CreateFilterAsync(fromAddress);
var logNewMessageEvents = await newMessageEvent.GetAllChanges<FunctionOutputHelpers.NewMessageEventArgs>(filterAllNewMessageEvent);
foreach (var mea in logNewMessageEvents)
{
Console.WriteLine("newMessageEvent:\t" +
mea.Event.sender + " " + mea.Event.ind.ToString() + " " + mea.Event.msg.ToString());
}
}

static public async Task GetContractValuesHistoryUniqueOffsetValueExample(Web3 web3, string contractAddress, HexBigInteger recentBlockNumber, ulong numberBlocks, int offset)
{
Console.WriteLine("GetContractValuesHistoryUniqueOffsetValueExample:");

string previousValue = "";
for (ulong blockNumber = (ulong)recentBlockNumber.Value; blockNumber > (ulong)recentBlockNumber.Value - numberBlocks; blockNumber--)
{
var blockNumberParameter = new Nethereum.RPC.Eth.DTOs.BlockParameter(blockNumber);
var valueAtOffset = await web3.Eth.GetStorageAt.SendRequestAsync(contractAddress, new HexBigInteger(offset), blockNumberParameter);
if (valueAtOffset != previousValue)
{
var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockNumberParameter);
DateTime blockDateTime = Helpers.UnixTimeStampToDateTime((double)block.Timestamp.Value);
Console.WriteLine("blockDateTime:\t" + blockDateTime.ToString());

for (int storageOffset = 0; storageOffset < offset+2; storageOffset++)
{
var valueAt = await web3.Eth.GetStorageAt.SendRequestAsync(contractAddress, new HexBigInteger(storageOffset), blockNumberParameter);
Console.WriteLine("value:\t" + blockNumber.ToString() + " " + storageOffset.ToString() + " " + valueAt + " " + Helpers.ConvertHex(valueAt.Substring(2)));
}
previousValue = valueAtOffset;
}
}
}
}
}

以下是一些支持文件:

FunctionOutputHelpers.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Nethereum.Web3;
using Nethereum.ABI.FunctionEncoding.Attributes;

namespace MWH.MyNethereum.QuickRef
{
static public class FunctionOutputHelpers
{
// event MultipliedEvent(
// address indexed sender,
// int oldProduct,
// int value,
// int newProduct
// );

[FunctionOutput]
public class MultipliedEventArgs
{
[Parameter("address", "sender", 1, true)]
public string sender { get; set; }

[Parameter("int", "oldProduct", 2, false)]
public int oldProduct { get; set; }

[Parameter("int", "value", 3, false)]
public int value { get; set; }

[Parameter("int", "newProduct", 4, false)]
public int newProduct { get; set; }

}

//event NewMessageEvent(
// address indexed sender,
// uint256 indexed ind,
// string msg
//);

[FunctionOutput]
public class NewMessageEventArgs
{
[Parameter("address", "sender", 1, true)]
public string sender { get; set; }

[Parameter("uint256", "ind", 2, true)]
public int ind { get; set; }

[Parameter("string", "msg", 3, false)]
public string msg { get; set; }
}
}
}

Helpers.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MWH.MyNethereum.QuickRef
{
static public class Helpers
{
public static string ConvertHex(String hexString)
{
try
{
string ascii = string.Empty;

for (int i = 0; i < hexString.Length; i += 2)
{
String hs = string.Empty;

hs = hexString.Substring(i, 2);
uint decval = System.Convert.ToUInt32(hs, 16);
char character = System.Convert.ToChar(decval);
ascii += character;

}

return ascii;
}
catch (Exception ex) { Console.WriteLine(ex.Message); }

return string.Empty;
}

public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
{
// Unix timestamp is seconds past epoch
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp); // .ToLocalTime();
return dtDateTime;
}

public static DateTime JavaTimeStampToDateTime(double javaTimeStamp)
{
// Java timestamp is milliseconds past epoch
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddMilliseconds(javaTimeStamp); // .ToLocalTime();
return dtDateTime;
}
}
}

以下是用于实施这些示例时使用的以太坊合约的Solidity代码:

Test3.sol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
pragma solidity 0.4.19;

contract Test3 {

int public _product;
string[5] _msgs;

event MultipliedEvent(
address indexed sender,
int oldProduct,
int value,
int newProduct
);

event NewMessageEvent(
address indexed sender,
uint256 indexed ind,
string msg
);

function Test3() public {
_product = 1;
}

function multiply(int value) public returns(int product) {
int old = _product;
_product = value * _product;
MultipliedEvent( msg.sender, old, value, _product );
return _product;
}

function getProduct() public constant returns(int product) {
return _product;
}

function setMsg(uint256 i, string m) public returns(uint256 mi) {
_msgs[i] = m;
NewMessageEvent( msg.sender, i, m);
return -i;
}

function getMsg(uint256 index) public constant returns(string m) {
return _msgs[index];
}
}

我觉得这是发布代码示例的一种相当简单粗暴的方式。有任何更好方法的建议都将受到赞赏。

======================================================================

如果你想马上使用c#开发以太坊dapp,可以学习下面的教程:

C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和事件等。

其他区块链教程:

  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容。
  • web3j教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • 以太坊教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • EOS智能合约与DApp开发入门教程,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后运用react和各知识点完成一个便签DApp的开发。

汇智网原创翻译,转载请标明出处。这里是原文