如果我们希望构造一个去中心化应用(DApp),除了智能合约的开发, 通常还需要使用其他开发语言为用户提供操作智能合约的用户接口,例如 开发一个网页、一个手机App或者一个桌面应用。这些代码都需要与以太坊 进行交互。本文是以C#做服务端开发,当然你也可以用java或者其他语言,大致的思想都是一样的。
开发以太网并进行交互的大致思想:
C#做服务端开发,处理业务逻辑,geth做客户端与服务器端进行交互,在remix上编写合约生成文件,然后获取remix生成的合约信息,在c#上通过代码将合约部署在geth上,之后就可以在代码里调用相应的合约。
首先是一篇github的项目,链接上面有步骤,按照步骤去下载软件环境以及驱动项目测试(这个很重要,因为我们也是基于这个项目框架去编写自己的项目需求的)
项目地址
然后是remix地址,推荐使用这个在浏览器上编写合约
有两个网址一个新版一个旧版:
旧版
新版
本篇博客使用新版的remix作为演示需要(稳定,易获取)
下面的代码演示也是基于上面的github开源项目的
- 首先是remix上编写一个helloworld的合约
有时候因为版本的问题,需要修改一下
pragma solidity ^0.4.0;//pragma 预编译 ^向上兼容
contract HelloWorld{
string Myname = "HelloWorld";
function getName() public view returns(string)//view 不会修改Myname等变量
{
return Myname;
}
function changeName(string _newName) public returns(string)
{
Myname = _newName;
return Myname;
}
}
- 然后需要将remix的合约编译&部署
需要导出它的ABI和ByteCode
实在不会操作或者想省事点的同志可以用我压缩过后的ABI文件,直接在vs项目里新建一个ABIHelloWorld.txt
[{ "constant":false,"inputs":[{ "name":"_newName","type":"string"}],"name":"changeName","outputs":[{ "name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{ "constant":true,"inputs":[],"name":"getName","outputs":[{ "name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]
ByteCode:这里需要将ByteCode文件的json字符串里的object的值复制出来,并在开头加一个0x,然后复制进BinHelloWorld.txt里就可以了。
0x60806040526040805190810160405280600a81526020017f48656c6c6f576f726c64000000000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6103f1806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806317d7de7c146100515780635353a2d8146100e1575b600080fd5b34801561005d57600080fd5b506100666101c3565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b50610148600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610265565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561018857808201518184015260208101905061016d565b50505050905090810190601f1680156101b55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606060008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561025b5780601f106102305761010080835404028352916020019161025b565b820191906000526020600020905b81548152906001019060200180831161023e57829003601f168201915b5050505050905090565b6060816000908051906020019061027d929190610320565b5060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103145780601f106102e957610100808354040283529160200191610314565b820191906000526020600020905b8154815290600101906020018083116102f757829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061036157805160ff191683800117855561038f565b8280016001018555821561038f579182015b8281111561038e578251825591602001919060010190610373565b5b50905061039c91906103a0565b5090565b6103c291905b808211156103be5760008160009055506001016103a6565b5090565b905600a165627a7a7230582063d64af44499532ae37de8529219d2226b9315188d19581c0a843a12cdca40be0029
- 主函数:
这边也是项目的入口
这边我是自己重新编写的一个DriAucContract类 - 然后就是测试合约的主要方法(都在DriAucContract类里)
Test2()
public async Task Test2()
{
await TestContractConnect();
}
TestContractConnect()函数
private async Task TestContractConnect()
{
Accounts = (await web3.Personal.ListAccounts.SendRequestAsync());//获取所以账号的string类型的地址
//....
var abi = File.ReadAllText("Contract\\abiHelloWorld.txt");
var bin = File.ReadAllText("Contract\\binHelloWorld.txt");
await web3.Personal.UnlockAccount.SendRequestAsync(Accounts[0], "123", 120);
TransactionReceipt receipt = await web3.Eth.DeployContract.SendRequestAndWaitForReceiptAsync(abi, bin, Accounts[0], new HexBigInteger(300000000), null);
testConnectContract = web3.Eth.GetContract(abi, receipt.ContractAddress);
changeName = testConnectContract.GetFunction(nameof(changeName));
getName = testConnectContract.GetFunction(nameof(getName));
String getResult1 = await getName.CallAsync<string>();
String getResult2 = await changeName.CallAsync<string>("welcome");
Console.WriteLine(string.Format("getResult1 = {0}\n getResult2 = {1}", getResult1, getResult2));
}
补充一下changeName ,getName ;是在DriAucContract类里定义的一个函数变量
Function getName,changeName;
Contract testConnectContract;
最后就是运行了,可能会有一些错误的处理,以后再贴一张调试成功的
图片
后面会上传测试合约的源码。
Remix
Geth
Vistual Studio2017
参考文章:
C#基于.net开发以太坊智能合约