platon 合约

admin
admin 2020年06月16日
  • 在其它设备中阅读本文章

PlatON 致力于建设下一代隐私计算架构和数据交换网络,基于现代密码技术和区块链技术,创造全新的计算范式,保证用户数据隐私的前提下,无需依赖第三方就可进行协同计算并验证结果的完整性。

创建并运行 debian10 镜像

docker run --name platon --restart always -itd debian:10

进入 debian 终端

docker exec -it platon /bin/bash

换源(加速下载包)和更新

/bin/bash -c 'echo -e "\
deb http://mirrors.163.com/debian/ buster main non-free contrib\n\
deb http://mirrors.163.com/debian/ buster-updates main non-free contrib\n\
deb http://mirrors.163.com/debian/ buster-backports main non-free contrib\n\
deb http://mirrors.163.com/debian-security/ buster/updates main non-free contrib" > /etc/apt/sources.list;\
apt update;\
apt upgrade -y;'

安装所需的包 ,编译程序和合约所需的库

apt install -y git gcc golang npm libgmp-dev libssl-dev libtinfo5 procps nano wget

安装 planton

git clone https://github.com/PlatONnetwork/PlatON-Go ~/PlatON-Go -b release-0.12.0 --depth 1 --recursive --shallow-submodules
cd ~/PlatON-Go && make all
echo 'export PATH="$HOME/PlatON-Go/build/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc

启动单节点测试网
1、生成 nodekey 和 blskey 等相关文件

mkdir -p ~/platon-node/data && keytool genkeypair | tee >(grep "PrivateKey" | awk '{print $2}' > ~/platon-node/data/nodekey) >(grep "PublicKey" | awk '{print $3}' > ~/platon-node/data/nodeid) && keytool genblskeypair | tee >(grep "PrivateKey" | awk '{print $2}' > ~/platon-node/data/blskey) >(grep "PublicKey" | awk '{print $3}' > ~/platon-node/data/blspub)

2、创建钱包文件,使用空白密码

mkdir -p ~/platon-node/data && platon --datadir ~/platon-node/data account new

3、在目录~/platon-node 下生成创世块配置文件 platon.json

nano ~/platon-node/platon.json

三个关键字段:

  • node 只修改节点公钥部分,查看 cat ~/platon-node/data/nodeid
  • blsPubKey 节点 BLS 公钥,查看 cat ~/platon-node/data/blspub
  • alloc 给测试账户配置一定的余额,之前生成的在目录 platon-node/data/keystore 下
    模板:

    {

      "config": {
          "chainId": 299,
          "eip155Block": 1,
          "ewasmBlock": 0,
          "VMInterpreter": "evm",
          "cbft": {
              "initialNodes": [{
                  "node": "enode://0fd7c8f228ff8549afd2a5a56cb688800b8b66706add2bc0a2190a09fee228d990e4a9f410b052e030abed9c6611f63798481992551cf3f3e4f8a736adfdc341@127.0.0.1:16789",
                  "blsPubKey": "8b0069a77e06da5ef94dad38ac74a26eee35a77c2b4ddd9397eb0ffa7f9d9210dc0f773ede77c9e5e3c45650d3dc5c14528ed063376d3ba295b219bccd322f8abd5f2432bade68149eeb97d544b2154700ff1b0d986b17e732b6fe64de6a6488"
              }],
              "amount": 10,
              "period": 10000,
              "validatorMode": "ppos"
          },
          "genesisVersion": 2304
      },
      "economicModel":{
          "common":{
              "maxEpochMinutes":4,
              "maxConsensusVals":4,
              "additionalCycleTime":28
          },
          "staking":{
              "stakeThreshold": 1000000000000000000000000,
              "operatingThreshold": 10000000000000000000,
              "maxValidators": 30,
              "HesitateRatio":1,
              "unStakeFreezeDuration": 2
          },
          "slashing":{
             "slashFractionDuplicateSign": 100,
             "duplicateSignReportReward": 50,
             "maxEvidenceAge":1,
             "slashBlocksReward":20,
             "zeroProduceCumulativeTime":3,
             "zeroProduceNumberThreshold":2
          },
           "gov": {
              "versionProposalVoteDurationSeconds": 160,
              "versionProposalSupportRate": 667,
              "textProposalVoteDurationSeconds": 160,
              "textProposalVoteRate": 5,
              "textProposalSupportRate": 667,          
              "cancelProposalVoteRate": 50,
              "cancelProposalSupportRate": 667,
              "paramProposalVoteDurationSeconds": 160,
              "paramProposalVoteRate": 50,
              "paramProposalSupportRate": 667      
          },
          "reward":{
              "newBlockRate": 50,
              "platonFoundationYear": 10 
          },
          "innerAcc":{
              "platonFundAccount": "0x493301712671ada506ba6ca7891f436d29185821",
              "platonFundBalance": 0,
              "cdfAccount": "0xc1f330b214668beac2e6418dd651b09c759a4bf5",
              "cdfBalance": 331811981000000000000000000
          }
      },
      "nonce": "0x0376e56dffd12ab53bb149bda4e0cbce2b6aabe4cccc0df0b5a39e12977a2fcd23",
      "timestamp": "0x5bc94a8a",
      "extraData": "0xd782070186706c61746f6e86676f312e3131856c696e757800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
      "gasLimit": "4712388",
      "alloc": {
          "1000000000000000000000000000000000000003": {
              "balance": "200000000000000000000000000"
          },
          "83837d7096180c8ed76b9b06770f4ffaec9b525e": {
            "balance": "999000000000000000000"
          }
      },
      "number": "0x0",
      "gasUsed": "0x0",
      "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"

    }

注:官方文档过期了,HesitateRatio 字段缺少和 gov 字段配置错误。

4、初始化创世区块

platon --datadir ~/platon-node/data init ~/platon-node/platon.json

5、启动单节点

cd ~/platon-node && (nohup platon --identity "platon" --datadir ./data --port 16789 --rpcaddr 127.0.0.1 --rpcport 6789 --rpcapi "db,platon,net,web3,admin,personal" --rpc --nodiscover --nodekey ./data/nodekey --cbft.blskey ./data/blskey & > ./data/platon.log 2>&1 &)

6、查看和验证

platon attach http://localhost:6789 --exec platon.blockNumber #区块高度
tail -f  nohup.out #打印日志跟踪
platon attach http://localhost:6789 --exec 'personal.unlockAccount(platon.accounts[0],"")' #解锁第一个账号

合约开发工具安装
1、安装 solc 编译器,platon 暂不支持高版本的 evm 字节码

npm i -g solc@0.5.6

2、安装 platon-cpp 编译器, 可以将 cpp 文件编译成 wasm 字节码

wget https://github.com/PlatONnetwork/PlatON-CDT/releases/download/v0.13.0/platon-cdt.tar.gz -O cdt.gz
tar -xvf cdt.gz -C /usr/local/ --strip-components 1 && rm cdt.gz

3、工具检查,包括platon-cppwasm-optsolcjs

ls -lh /usr/local/bin

platon 合约开发
1、创建合约文件目录

mkdir ~/helloworld

2、编辑 evm 合约 hello.sol 文件

nano ~/helloworld/hello.sol

模板:

pragma solidity >=0.5.0 <0.6.0;

contract Hello {
    struct Message{
        string head;
        string body;
        string end;
    }
    
    Message[] private mms;
    
    constructor(string memory a,string memory b, string memory c) public {
        mms.push(Message(a,b,c));
    }
    
    function add_message (string memory a,string memory b, string memory c) public {
        mms.push(Message(a,b,c));
    }
    
    function get_message_size () public view returns (uint8) {
        return uint8(mms.length);
    }
    
    function get_message_body (uint8 index) public view returns (string memory) {
        return mms[index].body;
    }
}

3、编辑 wasm 合约 hello.cpp 文件

nano ~/helloworld/hello.cpp

模板:

#include <platon/platon.hpp>
#include <string>
using namespace platon;

class message {
   public:
      std::string head;
      std::string body;
      std::string end;
      PLATON_SERIALIZE(message, (head)(body)(end))
};

CONTRACT HelloWorld : public platon::Contract{
   public:
      ACTION void init(const message &one_message){
        info.self().push_back(one_message);
      }

      ACTION void add_message(const message &one_message){
          info.self().push_back(one_message);
      }

      CONST uint8_t get_message_size(){
          return info.self().size();
      }

      CONST std::string get_message_body(const uint8_t index){
          return info.self()[index].body;
      }

   private:
      platon::StorageType<"myvector"_n, std::vector<message>> info;
};

PLATON_DISPATCH(HelloWorld, (init)(add_message)(get_message_size)(get_message_body))

4、编译合约

mkdir ~/helloworld/build && cd ~/helloworld
solcjs --abi --bin -o build hello.sol && platon-cpp -o build/hello.wasm hello.cpp

查看编译结果,包括 4 个文件,两个 abi 和两个字节码文件

ls -lh build

5、安装 js 调用工具

npm config set registry https://registry.npm.taobao.org && npm i lerna -g
cd ~/helloworld && npm i PlatONnetwork/client-sdk-js #github巨慢,重试直到成功

6、编辑合约部署调用 js 文件

nano ~/helloworld/evm.js

evm 合约部署调用实例:

const Web3 = require('web3');
const fs = require("fs");
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:6789'));
const code = "0x"+fs.readFileSync("./build/hello_sol_Hello.bin","utf-8");
var abi = JSON.parse(fs.readFileSync("./build/hello_sol_Hello.abi","utf-8"));
var contract = new web3.platon.Contract(abi,{data:code});
var defaultAccount

(async () => {
    // get and unlock default account
    await web3.platon.personal.getAccounts((err,accounts)=>{
       if (err) { throw(err) } 
       defaultAccount = accounts[0]
       console.log("default account:", defaultAccount)
    })
    console.log("unlock default account...")
    await web3.platon.personal.unlockAccount(defaultAccount, "").then((ret)=>{
        if (!ret) { throw("unlock account filed") }
        console.log("unlock success")
    })
    
    // contract deploy
    var data = contract.deploy({arguments: ["1","2","3"]}).encodeABI()
    console.log("contract deploy...")
    await web3.platon.sendTransaction({
        from:defaultAccount,
        data:data,
        gas:4100000,
        gaslimit:4800000
    },(err)=>{
        if (err) { throw(err) }
    }).then((receipt)=>{
        console.log("contract deploy success, receipt:",receipt)
        contract.options.address = receipt.contractAddress
    })
    
    // contract exec
    console.log("contract exec...")
    await contract.methods.add_message("5","7","8").send({
       from:defaultAccount,
       gas:1000000
    }).then((receipt)=>{
       console.log("contract exec success, receipt:", receipt)
    })
    
    // contract call
    console.log("contract call...")
    await contract.methods.get_message_body(1).call().then((ret)=>{
       console.log("contract call success, result:", ret)
    })
})().catch(err => console.log(err));

nano ~/helloworld/wasm.js

wasm 合约部署调用实例:

const Web3 = require('web3');
const fs = require("fs");
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:6789'));
const bin = fs.readFileSync("./build/hello.wasm");
var abi = JSON.parse(fs.readFileSync("./build/hello.abi.json","utf-8"));
var contract = new web3.platon.Contract(abi,{vmType:1});
var defaultAccount

(async () => {
    // get and unlock default account
    await web3.platon.personal.getAccounts((err,accounts)=>{
       if (err) { throw(err) } 
       defaultAccount = accounts[0]
       console.log("default account:", defaultAccount)
    })
    console.log("unlock default account...")
    await web3.platon.personal.unlockAccount(defaultAccount, "").then((ret)=>{
        if (!ret) { throw("unlock account filed") }
        console.log("unlock success")
    })
    
    // contract deploy
    var data = contract.deploy({data:bin.toString("hex"), arguments: [[["1"],"2","3"]]}).encodeABI()
    console.log("contract deploy...")
    await web3.platon.sendTransaction({
        from:defaultAccount,
        data:data,
        gas:4100000,
        gaslimit:4800000
    },(err)=>{
        if (err) { throw(err) }
    }).then((receipt)=>{
        console.log("contract deploy success, receipt:",receipt)
        contract.options.address = receipt.contractAddress
    })
    
    // contract exec
    console.log("contract exec...")
    await contract.methods.add_message([["5"],"7","8"]).send({
        from:defaultAccount,
        gas:1000000
    }).then((receipt)=>{
        console.log("contract exec success, receipt:", receipt)
    })
    
    // contract call
    console.log("contract call...")
    await contract.methods.get_message_body(1).call().then((ret)=>{
        console.log("contract call success, result:", ret)
    })
})().catch(err => console.log(err));

7、部署调用合约
启动节点:

cd ~/platon-node && (nohup platon --identity "platon" --datadir ./data --port 16789 --rpcaddr 127.0.0.1 --rpcport 6789 --rpcapi "db,platon,net,web3,admin,personal" --rpc --nodiscover --nodekey ./data/nodekey --cbft.blskey ./data/blskey & > ./data/platon.log 2>&1 &)

8、执行 js 文件调用,查看打印验证合约是否执行成功

cd ~/helloworld && node evm.js && node wasm.js