platon 合约
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-cpp
、wasm-opt
、solcjs
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