Skip to content

Latest commit

 

History

History
215 lines (156 loc) · 5.32 KB

智能合约编写.md

File metadata and controls

215 lines (156 loc) · 5.32 KB

智能合约编写

aelf 通过类GRPC的protobuf服务描述文件定义智能合约,实现了一个性能等价于GRPC Server的智能合约运行环境。

Hello World 智能合约讲解

简化目录结构

.
├── AElf.Boilerplate.sln
├── protobuf
│   ├── hello_world.proto
├── src
│   ├── AElf.Boilerplate.Launcher
│   │   ├── bin
│   │   │   └── Debug
│   │   │       └── netcoreapp2.2
│   │   │           ├── AElf.Boilerplate.Launcher.dll
│   └── HelloWorldContract
│   │   ├── bin
│   │   │   └── Debug
│   │   │       └── netcoreapp2.2
│   │   │           ├── HelloWorldContract.dll
│       ├── HelloWorldContract.cs
│       ├── HelloWorldContract.csproj

1.在protobuf/hello_world.proto中

通过service 定义了对应的rpc方法,通过message来定义了数据格式。更多的内容可以参考protobuf的文档。

2.在src/HelloWorldContract中

在HelloWorldContract.csproj引用了对应的protobuf文件。

在HelloWorldContract.cs中实现了具体的合约逻辑。

3.src/HelloWorldContract/bin/Debug/netcoreapp2.2/HelloWorldContract.dll

这个文件是执行 dotnet build后生成的文件。

在boilerplate这个模板中,dotnet run时会自动发布到我们启动的链上。

如果需要将自己的合约发布到其它基于AELF系统运行的区块链网络上,只需要发布对应dll即可。

4.代码讲解

// protobuf的定义
syntax = "proto3";

import "aelf_options.proto";
import "google/protobuf/empty.proto";

option csharp_namespace = "HelloWorldContract";

service HelloWorldContract {

    option (aelf.csharp_state) = "HelloWorldContractState";

    // 定义了合约的方法,和该方法的返回
    rpc Hello (google.protobuf.Empty) returns (HelloReturn) { }
}

// 定义了返回数据的数据格式
message HelloReturn {
    string Value = 1;
}
// C#中的逻辑实现
using Google.Protobuf.WellKnownTypes;

namespace HelloWorldContract
{
    public partial class HelloWorldContract : HelloWorldContractContainer.HelloWorldContractBase
    {
        // 对应proto文件中的rpc Hello
        // 返回为 HelloReturn
        public override HelloReturn Hello(Empty input)
        {
            return new HelloReturn {Value = "Hello world!"};
        }
}

新增合约方法教程

下面我们新增一个Add方法,输入两个整型参数 a和b, 输出 a + b

1.在hello_world.proto文件中增加方法的定义和数据类型的定义

syntax = "proto3";

import "aelf_options.proto";
import "google/protobuf/empty.proto";

option csharp_namespace = "HelloWorldContract";

service HelloWorldContract {

    option (aelf.csharp_state) = "HelloWorldContractState";

    rpc Hello (google.protobuf.Empty) returns (HelloReturn) { }

    // 新增方法Add, 入参为AddInput, 返回为 AddOutput
    rpc Add (AddInput) returns (AddOutput) { }
}

message HelloReturn {
    string Value = 1;
}

// AddInput的格式定义,根据protobuf的协议规定,Key的首字母须大写
message AddInput {
    sint64 A = 1;
    sint64 B = 2;
}

// AddOutpu的定义
message AddOutput {
    sint64 Value = 1;
}

2.在HelloWorldContract.cs新增逻辑

using Google.Protobuf.WellKnownTypes;

namespace HelloWorldContract
{
    public partial class HelloWorldContract : HelloWorldContractContainer.HelloWorldContractBase
    {
        public override HelloReturn Hello(Empty input)
        {
            return new HelloReturn {Value = "Hello world!"};
        }

        // 新增Add方法
        public override AddOutput Add(AddInput input) {
            return new AddOutput {Value = input.A + input.B};
        }
    }
}

3.重新编译并启动链

在src/AElf.Boilerplate.Launcher 下执行 dotnet build 完成编译

dotnet run bin/Debug/netcoreapp2.2/AElf.Boilerplate.Launcher

新的合约会自动发布到链上。

4.通过JS文件使用新的合约

cd web/JSSDK
# 执行node, 进入nodejs的命令行交互界面
node

把下面一段js输入

const AElf = require('aelf-sdk');
const Wallet = AElf.wallet;
const sha256 = AElf.utils.sha256;

// address: 65dDNxzcd35jESiidFXN5JV8Z7pCwaFnepuYQToNefSgqk9
const defaultPrivateKey = 'bdb3b39ef4cd18c2697a920eb6d9e8c3cf1a930570beb37d04fb52400092c42b';

const wallet = Wallet.getWalletByPrivateKey(defaultPrivateKey);
const aelf = new AElf(new AElf.providers.HttpProvider(
    'http://127.0.0.1:1235/chain',
    null,
    null,
    null,
    [{
        name: 'Accept',
        value: 'text/plain;v=1.0'
    }]
));

const helloWorldContractName = 'HelloWorldContract';
const {
    GenesisContractAddress
} = aelf.chain.getChainStatus();
const zeroC = aelf.chain.contractAt(GenesisContractAddress, wallet);
const helloWorldContractAddress = zeroC.GetContractAddressByName.call(sha256(helloWorldContractName));
const helloWorldC = aelf.chain.contractAt(helloWorldContractAddress, wallet);

// 刚新增的方法
helloWorldC.Add.call({A: 1, B:3}, (error, result) => {console.log(error, result);})

稍等一下看到输出结果

null { Value: '4' }

看不到结果

  1. 确认编译成功。

  2. 确认链在运行。

  3. 确认JS代码没输入错。

多学多看多搜索,愿大家在工程师的道路上越走越远。