Conflux入门心得汇总
概念
参考资料:
- https://developer.confluxnetwork.org 开发者文档
- https://docs.confluxnetwork.org/go-conflux-sdk sdk文档
- https://zhuanlan.zhihu.com/p/400583419 https://zhuanlan.zhihu.com/p/393935101 NFT部署教程
树图结构
由开发者文档所示, 与传统的以太坊的链式结构不同, 该结构是类似于IoTA的有向无环图(DAG)结构的, 具体结构可自行查阅.
基本概念
CFX
CFX为conflux中的token, 对应于以太坊中的Ether. conflux中有多种代币单位, 包括Drip,GDrip, uCFX, CFX. 这几种代币之间的进率如下图所示:
CFX用处
- 参与链治理 -> 拥有CFX的用户可以参与链治理, 发起投票
- 发送交易: 包括转账, 部署与调用合约等
- 抵押(staking mechanism):
CFX获取
-
挖矿: 当挖到相应的区块后可以获得分红. 分红包括:
- 固定奖励2CFX
- 执行交易获得的费用
- 所有抵押代币所获得的年化率4%的回报(需要加入PoS)
-
抵押: 将自己的代币抵押给内置合约, 从而使得该账户参与链治理的权力变大. 内置合约根据规则支付年化4%的回报
-
转账: 通过从其他账户转账从而获得代币
ChainID 与 NetworkID
顾名思义, 对链与网络的一个标识
注意点
- ChainID在主网为1029, 在测试网为1
- ChainID可以用来对抗交易重放攻击(transaction replay attacks)
- NetworkID与ChainID相同
地址
conflux地址为base32形式, 满足cip317(一种编码方式, 提高安全性且增加了可读性), 与以太坊相对
例子如下:
16 进制地址:0x1386b4185a223ef49592233b69291bbe5a80c527
base32地址:cfx:aak2rra2njvd77ezwjvx04kkds9fzagfe6ku8scz91
在以太坊的common.Address
是以16进制的方式存储, 可调用base32地址的GetHexString
获得, 也就是说, conflux地址与以太坊地址间存在一对一映射关系
账户
存储与以太坊相同, 以 地址-> 状态的键值对以kvstore存储在MPT树当中
与以太坊账户相同的部分: nonce
, balance
, codeHash
(合约账户)
CONFLUX特有的部分: stakingBalance
, storageCollateral
, accumulatedInterestReturn
, admin
, sponsorInfo
具体解释可以查看(https://developer.confluxnetwork.org/introduction/en/conflux_basics)
交易
大致的field与以太坊相同, 主要有from
, to
, nonce
, gasPrice
, gas
, value
, chainId
, data
, v, r, s
这些field的意义也与以太坊相同
conflux特殊的是有epochHeight
字段与storageLimit
, 跟区块高度相对, conflux的共识是以epoch去表征区块深度的
交易的生命周期
- 准备发送者的私钥和地址
- 准备交易的元数据,组装成交易, 并将其encode(keccak256), 私钥进行签名(ECDSA), 再用rlp进行encode -> hexString -> rawtransaction
- 通过rpc方法, 将rawtransaction发送至全节点的交易池
- 交易被矿工打包进区块
- 等待5个epoch -> 状态变为executed, 执行交易 (本地状态进行更新?)
- 等待50个epoch -> 状态变为confirmed, 交易被承认 (若未被承认, 则状态回滚) 承认机制, 比较epoch大小
- 等待被区块链引用至链上 -> 状态变为Finalized, 完结 (全局状态进行更新?)
与ETH的区别
https://developer.confluxnetwork.org/sending-tx/en/transaction_explain#:~:text=no%20details%20provided.-,Differences%20between%20Conflux%20and%20Ethereum,-%23
存储
需要锁一定数量的资金作为质押, 来作为执行交易时所使用storage需要付出的token, 账户这部分的token会被锁; 计算公式为
X B/64 *(1/16)
# 64字节为一个storage entry
当存储空间的所有权转移时, 新拥有者的token会被锁, 旧拥有者的token会被解除锁定, 并被加回旧拥有者的账户(不发生转账交易, 无法查询)
内置合约
主要有三个合约: AdminControl contract
, SponsorWhitelistControl contract
, Staking Contract
AdminControl contract
创建合约账户的账户成为该合约的admin, 拥有包括destroy, 白名单等多项权力, 该admin权限可以转移
例子:
- A在创建了合约B, 并在合约构建阶段将权力给了C -> C是admin
- A调用合约B, 合约B创建了合约C, 且合约C在合约构建阶段将D设为admin. -> 设为admin操作失败, A是C的管理员, B只是消息传递者
- 若在例子2中, D地址为零, 则可以成功, 则C没有admin
SponsorWhitelistControl contract
使得余额为零的账户能够调用合约, 该费用由sponsor来支付. 条件:
- 调用小于sponsor的上限(该上限可以由sponsor调整)
- 调用账户在白名单当中(白名单只有admin与合约本身可以改, sponsor不能改)
- sponsor关系可以转移
Staking Contract
账户可以将token质押, 从而获取相应的storage和链治理当中的投票权
注意: 质押操作会被更强大的承诺所覆盖, 如, 明年质押1CFX, 与明年质押2CFX相比. (更强大的比较只是token数量?)
实践
建议在Linux与OSX环境下执行·, Windows需要vs编译器过于不友好
安装环境
根据开发者文档步骤, 安装环境 https://developer.confluxnetwork.org/conflux-doc/docs/installation
启动私有链
修改配置文件
在项目目录下进入run
目录
cd run
复制主网toml文件为开发toml文件
cp hydra.toml develpoment.toml
修改development.toml
mode = "dev"
genesis_secrets = "key.txt" ##这个后面需要用
dev_block_interval_ms = 250
jsonrpc_http_port=12537 ##用jsonrpc_local_http_port=12539也可以, 钱包的localhost是12537
从钱包网站上按照步骤获得keystore, 或是从github项目中获取keystore
https://github.com/conflux-fans/conflux-abigen-example/tree/main/keystore
https://wallet.confluxscan.io/login
拉取go-sdk代码
go get github.com/Conflux-Chain/go-conflux-sdk
调用sdk在keystore中创建账户, 并导出账户私钥
func createAcc(client *conflux.Client){
client, err := conflux.NewClient(local_url, conflux.ClientOption{
KeystorePath: ".keystore"}) //local_url = "http://127.0.0.1:12537"
if err != nil {
panic(err)
}
defer client.Close()
acc1,err := client.AccountManager.Create("test")
if err != nil {
log.Fatalln(err)
}
fmt.Println(acc1.String())
acc2,err := client.AccountManager.Create("test")
if err != nil {
log.Fatalln(err)
}
fmt.Println(acc2.String())
}
func exportPriKeys(client *conflux.Client){
list := client.GetAccountManager().List()
priv1, err := client.GetAccountManager().Export(list[0], "test")
if err != nil {
panic(err)
}
priv2, err := client.GetAccountManager().Export(list[1], "test")
if err != nil {
panic(err)
}
fmt.Println(priv2)
fmt.Println(priv1)
}
在run目录下将输出的私钥写入key.txt, 一行一串私钥, 由此对应的账户会被分配1000cfx
vim key.txt
清除链上数据, 并重启
sh clear_state.sh
sh test.sh
test.sh :
export RUST_BACKTRACE=1
export RUST_BACKTRACE=full
../target/release/conflux --config development.toml
发送交易
发送交易的sdk如下
func sendTx(client *conflux.Client){
list := client.GetAccountManager().List()
var utx types.UnsignedTransaction
utx.From = &list[0] //use default account if not set
utx.To = &list[1]
// unlock account
err = client.AccountManager.Unlock(acc1, "test")
if err != nil {
log.Fatal(err)
}
txhash, err := client.SendTransaction(utx)
if err != nil {
log.Fatal(err)
}
fmt.Println(txhash)
}
部署与调用合约
部署合约与调用合约基于cfxabigen, 参考https://docs.confluxnetwork.org/go-conflux-sdk/cfxabigen
下载代码
git clone https://github.com/Conflux-Chain/go-conflux-sdk.git
安装工具
go install ./cmd/cfxabigen
ERC20
根据示例生成go文件
cfxabigen --sol token.sol --pkg main --out token.go >> token.go
接着部署与调用合约可完全参考https://github.com/conflux-fans/conflux-abigen-example/blob/main/token/main.go
ERC721
在理解了上述ERC20步骤后, 可参考 https://zhuanlan.zhihu.com/p/400583419 和https://zhuanlan.zhihu.com/p/393935101 进行ERC721合约的部署与调用
首先, 编译合约需要依赖Openzeppelin
需要安装npm
sudo apt install npm
安装Openzeppelin库
npm install @openzeppelin/contracts
在remix中进行编译从而得到字节码与abi, 将其分别写入nft.bin与nft.abi中(注:其中ipfs中的url可以为自己生成的, 也可随意)
用cfxabigen工具进行编译
cfxabigen --abi nft.abi --bin nft.bin --pkg main --out nft.go >> nft.go
根据nft.go进行如下sdk编写
部署合约
func deployNFT(client *conflux.Client){
err := client.AccountManager.UnlockDefault("test1")
if err != nil {
log.Fatal(err)
}
//tx, hash, t, err := DeployMain(nil, client)
tx, hash, _, err := DeployMain(nil, client)
if err != nil {
panic(err)
}
fmt.Println(tx)
fmt.Println(hash)
receipt, err := client.WaitForTransationReceipt(*hash, time.Second)
if err != nil {
panic(err)
}
logrus.WithFields(logrus.Fields{
"tx": tx,
"hash": hash,
"contract address": receipt.ContractCreated,
}).Info("deploy token done")
}
调用铸造NFT
func mintNFT(client *conflux.Client) {
acc, _ := client.GetAccountManager().GetDefault()
err := client.AccountManager.UnlockDefault("test")
if err != nil {
panic(err)
}
contractAddr := cfxaddress.MustNew("cfx:acdujjy8mrjm3913cnztf0zbgpx5h3fbby7jcwp2pc")
instance, err := NewMain(contractAddr, client)
if err != nil {
panic(err)
}
err = client.AccountManager.UnlockDefault("test")
if err != nil {
panic(err)
}
//to := cfxaddress.MustNew("cfx:aap05tb7b9bsxdn5rn365y3peta8pr6mxefp7m682a")
comacc, _, _ := acc.ToCommon()
tx, hash, err := instance.Mint(nil, comacc)
if err != nil {
panic(err)
}
logrus.WithField("tx", tx).WithField("hash", hash).Info("transfer")
receipt, err := client.WaitForTransationReceipt(*hash, time.Second)
if err != nil {
panic(err)
}
logrus.WithField("transfer receipt", receipt).Info()
}
查询账户拥有的nft
func queryNFT(client *conflux.Client){
acc, _ := client.GetAccountManager().GetDefault()
err := client.AccountManager.UnlockDefault("test1")
if err != nil {
panic(err)
}
contractAddr := cfxaddress.MustNew("cfx:acdujjy8mrjm3913cnztf0zbgpx5h3fbby7jcwp2pc")
instance, err := NewMain(contractAddr, client)
if err != nil {
panic(err)
}
comacc, _, _ := acc.ToCommon()
res, err := instance.MainCaller.BalanceOf(nil, comacc)
if err != nil {
panic(err)
}
res1, _ := instance.MainCaller.Symbol(nil)
fmt.Println(res)
fmt.Println(res1)
}
调用后可以获得账户对应的nft和nft对应的symbol
转移nft
func transferNFT(client *conflux.Client){
acc, _ := client.GetAccountManager().GetDefault()
err := client.AccountManager.UnlockDefault("test1")
if err != nil {
panic(err)
}
contractAddr := cfxaddress.MustNew("cfx:acdujjy8mrjm3913cnztf0zbgpx5h3fbby7jcwp2pc")
instance, err := NewMain(contractAddr, client)
if err != nil {
panic(err)
}
comacc, _, _ := acc.ToCommon()
list := client.GetAccountManager().List()
toacc, _, _ := list[len(list)-1].ToCommon()
err = client.AccountManager.Unlock(list[len(list)-1], "test")
if err != nil {
panic(err)
}
id := big.NewInt(0)
tx, hash, err := instance.TransferFrom(nil, comacc, toacc, id)
if err != nil {
panic(err)
}
receipt, err := client.WaitForTransationReceipt(*hash, time.Second)
if err != nil {
panic(err)
}
logrus.WithFields(logrus.Fields{
"tx": tx,
"hash": hash,
"contract address": receipt.ContractCreated,
}).Info("deploy token done")
res, err := instance.MainCaller.BalanceOf(nil, comacc)
if err != nil {
panic(err)
}
res1, err := instance.MainCaller.BalanceOf(nil, toacc)
if err != nil {
panic(err)
}
fmt.Println(res)
fmt.Println(res1)
}
查询后可以发现一个为0, 一个为1, 则转移成功
No Comments