Conflux js-sdk与以太坊web3. js区别

Web3.js vs js-conflux-sdk

js-conflux-sdk 最新版本为1.x, 与0.x有很大差别, 但由于其还在测试阶段,本文只对0.13.4Web3进行对照,待1.x版本稳定后, 再针对1.x与Web3进行对照。
Web3js-conflux-sdk 都是最顶层模块,他们包含了其它子模块以及在顶层暴露了一些子模块中的方法方便开发者快捷使用,我们这里只比较各模块,而不再对这些快捷方法做特别说明。

模块对比

Web3js-conflux-sdk 有对应关系的主要有以下模块:

Ethereum中的模块 Conflux中的模块 功能
Eth Conflux 用于管理连接节点,与节点交互,发送rpc请求,包含读取状态、发送交易等
Contract + abi Contract 用于操作智能合约,包含创建合约实例、调动合约方法,以及提供一些根据abi编解码的功能
accounts account + Message + Transaction 用于管理账户,包含创建、删除账户,及使用账户对消息或交易进行签名等操作
utils util 工具类,提供一些通用函数,例如hex格式转换,单位转换,私钥转公钥及地址,生成随机私钥,判断数据类型,sha3等,方便dapp开发及其他js包使用

各模块方法对比

Conflux模块 Vs Eth模块

以下是Conflux模块包含的方法及与Eth模块的对应关系,该模块主要封装了JSONRPC与节点交互,还有一部分JSONRPC暂未实现,将来会不断完善RPC。。具体RPC介绍请参见 Conflux JSONRPC介绍Conflux RPC与Ethereum RPC的区别
这里的Epoch Number指用于划分一组Conflux区块为一个Epoch,Conflux区块链是以Epoch为顺序组织的。

Conflux模块 Ethereum Eth模块 对应RPC
setProvider setProvider -
getStatus getChainId cfx_getStatus
getGasPrice getGasPrice cfx_gasPrice
getEpochNumber getBlockNumber cfx_epochNumber
getBalance getBalance cfx_getBalance
getNextNonce getBlockTransactionCount cfx_getNextNonce
getBlockByEpochNumber getBlock cfx_getBlockByEpochNumber
getBlocksByEpochNumber - cfx_getBlocksByEpoch
getBlockByHash getBlock cfx_getBlockByHash
getBlockByHashWithPivotAssumption - cfx_getBlockByHashWithPivotAssumption
getTransactionByHash getTransaction cfx_getTransactionByHash
getTransactionReceipt getTransactionReceipt cfx_getTransactionReceipt
sendTransaction sendTransaction cfx_sendTransaction
sendRawTransaction sendSignedTransaction cfx_sendRawTransaction
getCode getCode cfx_getCode
call call cfx_call
estimateGasAndCollateral estimateGas cfx_estimateGasAndCollateral
getLogs getPastLogs(contract模块) cfx_getLogs
getBestBlockHash - cfx_getBestBlockHash
getConfirmationRiskByHash - cfx_getConfirmationRiskByHash
close - -

Contract 模块对比

Conflux Contract 模块 Eth Contract + abi 模块
contract.mymethod methods.myMethod.call
contract.mymethod.call methods.myMethod.call
contract.mymethod.decodeData decodeParameters
contract.mymethod.decodeOutputs -
contract.mymethod.encodeData methods.myMethod.encodeABI
contract.mymethod.send methods.myMethod.send
contract.mymethod.estimateGasAndCollateral methods.myMethod.estimateGas
contract.myEvent.getLogs getPastLogs
contract.myEvent.encodeTopics -
contract.myEvent.decodeLog decodeLog(ABI模块)
contract.abi.decodeData decodeParameters
contract.abi.decodeLog decodeLog(ABI模块)

accounts 模块对比

Conflux Account模块 Ethereum Accounts模块
random create
decrypt decrypt
encrypt encrypt
signTransaction signTransaction
signMessage sign
Conflux Message模块 Ethereum Accounts模块
sign sign
recover recover
hash (getter) -
from (getter) -
sign sign
Conflux Transaction模块 Ethereum Accounts模块
hash (getter) -
from (getter) -
sign signTransaction
recover recover
encode -
serialize -

utils 模块对比

Conflux util 模块 Ethereum utils模块
format.any (setter) -
format.hex (setter) toHex, numberToHex
format.uInt (setter) -
format.bigInt (setter) toBN
format.bigUInt (setter) -
format.hexUInt (setter) -
format.riskNumber (setter) -
format.epochNumber (setter) -
format.address (setter) bytesToHex
format.publicKey (setter) bytesToHex
format.privateKey (setter) bytesToHex
format.signature (setter) bytesToHex
format.blockHash (setter) bytesToHex
format.txHash (setter) bytesToHex
format.buffer (setter) toHex + hexToBytes
format.boolean (setter) -
sha3 sha3
checksumAddress toChecksumAddress
randomBuffer -
randomPrivateKey randomHex
privateKeyToPublicKey privateKeyToAccount(Accounts模块)
publicKeyToAddress privateKeyToAccount(Accounts模块)
privateKeyToAddress privateKeyToAccount(Accounts模块)
ecdsaSign sign(Accounts模块)
ecdsaRecover recover(Accounts模块)
encrypt encrypt(Accounts模块)
decrypt decrypt(Accounts模块)
unit.fromCFXToGDrip -
unit.fromCFXToDrip toWei
unit.fromGDripToCFX -
unit.fromGDripToDrip -
unit.fromDripToCFX fromWei
unit.fromDripToGDrip -

使用对比

初始化

初始化Web3实例

var Web3 = require('web3');
// "Web3.providers.givenProvider" will be set if in an Ethereum supported browser.
var web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');
// or
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));

初始化Conflux实例

Conflux实例化与web3类似,但当前版本还不支持 webscoket provider

const { Conflux } = require('js-conflux-sdk');
const cfx = new Conflux({url:'http://test.confluxrpc.org'});

读状态

Ethereum读状态

web3.eth.getBalance("0x107d73d8a49eeb85d32cf465507dd71d507100c1").then(console.log);
> "1000000000000"

Conflux读状态

await cfx.getBalance("0x107d73d8a49eeb85d32cf465507dd71d507100c1");
// or
cfx.getBalance("0x107d73d8a49eeb85d32cf465507dd71d507100c1").then(console.log)
> "1000000000000"

发送交易

web3 发送交易

web3发送交易后通过event方式在以下各个阶段达成时通知:

  • transactionHash 交易已发送
  • receipt 交易已执行
  • confirmation 交易已确认
  • error 交易执行失败
// compiled solidity source code using https://remix.ethereum.org
var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3";

// using the callback
web3.eth.sendTransaction({
    from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
    data: code // deploying a contracrt
}, function(error, hash){
    ...
});

// using the promise
web3.eth.sendTransaction({
    from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
    to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',
    value: '1000000000000000'
})
.then(function(receipt){
    ...
});

// using the event emitter
web3.eth.sendTransaction({
    from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
    to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',
    value: '1000000000000000'
})
.on('transactionHash', function(hash){
    ...
})
.on('receipt', function(receipt){
    ...
})
.on('confirmation', function(confirmationNumber, receipt){ ... })
.on('error', console.error); // If a out of gas error, the second parameter is the receipt.

Conflux发送交易

js-conflux-sdk 由于当前版本没有增加访问节点本地钱包功能,所以发送交易时需要直接指定Account; sendTransaction返回的是一个 Promise.<PendingTransaction>对象, 可以直接await获取transaction hash

也可以通过该对象方法在不同状态下返回transactiontransaction receipt, 方法列举如下:

  • get在发送完成后返回transaction,
  • mined在打包完成后返回transaction,
  • executed在执行完成后返回transaction receipt,
  • confirmedtransaction risk < threshold时返回transaction receipt
const account = cfx.Account(your_private_key);

const promise = cfx.sendTransaction({ // Not await here, just get promise
      from: account,
      to: "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",
      value: Drip.fromCFX(0.007),
    });
> await promise; // transaction
   "0x91fbdfb33f3a585f932c627abbe268c7e3aedffc1633f9338f9779c64702c688"
> await promise.get(); // get transaction
   {
    "blockHash": null,
    "transactionIndex": null,
    "hash": "0x91fbdfb33f3a585f932c627abbe268c7e3aedffc1633f9338f9779c64702c688",
    ...
   }
> await promise.mined(); // wait till transaction mined
   {
    "blockHash": "0xe9b22ce311003e26c7330ac54eea9f8afea0ffcd4905828f27c9e2c02f3a00f7",
    "transactionIndex": 0,
    "hash": "0x91fbdfb33f3a585f932c627abbe268c7e3aedffc1633f9338f9779c64702c688",
    ...
   }
> await promise.executed(); // wait till transaction executed in right status. and return it's receipt.
   {
    "blockHash": "0xe9b22ce311003e26c7330ac54eea9f8afea0ffcd4905828f27c9e2c02f3a00f7",
    "index": 0,
    "transactionHash": "0x91fbdfb33f3a585f932c627abbe268c7e3aedffc1633f9338f9779c64702c688",
    "outcomeStatus": 0,
    ...
   }
> await promise.confirmed(); // wait till transaction risk coefficient '<' threshold.
   {
    "blockHash": "0xe9b22ce311003e26c7330ac54eea9f8afea0ffcd4905828f27c9e2c02f3a00f7",
    "index": 0,
    "transactionHash": "0x91fbdfb33f3a585f932c627abbe268c7e3aedffc1633f9338f9779c64702c688",
    "outcomeStatus": 0,
    ...
   }
需要注意的地方:

发送交易时,建议先使用 estimateGasAndCollateral 返回预估的gas使用数量和存储抵押数量;然而由于实际执行消耗与预估结果有差异,为了防止交易执行失败,建议在实际发送交易时,设置gaslimitstorage_limit的值为预估值 * 4/3

参数EpochHeight表示这笔交易将会在 Epoch[EpochHeight-100000 , EpochHeight+100000] 的区间内执行,当超出这个区间这笔交易将被丢弃,建议设置当前Epoch值即可。

部署合约

部署合约实质就是发送一笔data为合约bytecodetonull的交易

web3部署合约

web3可以通过直接发送交易的方式部署,也可以通过contract实例部署

// send transaction directly
await web3.eth.sendTransaction({
    from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
    data: contract_bytecode,
})
> {
  "status": true,
  "contractAddress": "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",
  ...
}

// or use contract instance
var myContract = new web3.eth.Contract(contract_abi, '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', {
    from: '0x1234567890123456789012345678901234567891', // default from address
    ...
});
myContract.deploy({
    data: '0x12345...',
    arguments: [123, 'My String']
})
.send({
    from: '0x1234567890123456789012345678901234567891',
    gas: 1500000,
    gasPrice: '30000000000000'
}, function(error, transactionHash){ ... })
.on('error', function(error){ ... })
.on('transactionHash', function(transactionHash){ ... })
.on('receipt', function(receipt){
   console.log(receipt.contractAddress) // contains the new contract address
})
.on('confirmation', function(confirmationNumber, receipt){ ... })
.then(function(newContractInstance){
    console.log(newContractInstance.options.address) // instance with the new contract address
});

conflux部署合约

conflux当前只能通过发送交易的方式部署,transaction receiptcontractCreated字段就是部署后的合约地址。注意contract_bytecode数据需要0x开头的数据。

const account = cfx.Account(your_private_key);

await cfx.sendTransaction({ // Not await here, just get promise
      from: account,
      data: contract_bytecode,
    }).executed();
>  {
   "outcomeStatus": 0,
   "contractCreated": "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",
   ...
   }

调用合约

调用合约分两种:

  • 一种是读状态,不需要发送交易,读状态web3跟conflux都使用call方法。
  • 一种是修改合约状态,需要发送交易,修改合约状态web3使用send,conflux使用sendTransaction

web3调用合约

// create contract instance
var myContract = new web3.eth.Contract(contract_abi, contract_address);

// calling a method
myContract.methods.myMethod(123).call({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'}, function(error, result){
    ...
});

// or sending and using a promise
myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.then(function(receipt){
    // receipt can also be a new contract instance, when coming from a "contract.deploy({...}).send()"
    ...
});

conflux调用合约

conflux 调用合约与web3类似,需要注意的地方是调用合约发送交易前建议根据estimateGasAndCollateral得到的gasUsed与storageCollateralized计算gas(同以太坊的gasLimit)与storageLimit; 由于实际执行交易时使用的gas与storageCollateralized与预估可能会有差别,为了防止失败,建议设置 gas = estimated.gasUsed * 4 / 3,storageLimit = estimated.storageCollateralized * 4 /3

// create contract instance
var myContract = cfx.Contract({
    abi: contract_abi,
    address: contract_address
});

// call
await contract.myCallMethod(123)
await contract.myCallMethod().call(123)

// send
// set gasLimit and sotrageLimit large 1/3 than estimated value
const estimated = await contract.mySendMethod(123).estimateGasAndCollateral({from: '0x1e0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'});
let gasLimit = JSBI.multiply(estimated.gasUsed, JSBI.BigInt(4))
gasLimit = JSBI.divide(gasLimit, JSBI.BigInt(3))
let storageLimit = JSBI.multiply(estimated.storageCollateralized, JSBI.BigInt(4))
storageLimit = JSBI.divide(storageLimit, JSBI.BigInt(3))

// send transaction
await contract.mySendMethod(123).sendTransaction({from: "addres",gasLimit:estimated.gas*4/3}).executed();

eth 中的其它模块

除了以上介绍的模块,web3中还包含了以下模块;这些模块conflux中暂时还没有对应模块,将来可能支持类似功能

web3模块 作用
personal 使用所请求节点的账户进行签名、锁定、解锁等操作
shh 用于使用whisper协议传播消息
bzz 用于与swarm交互,swarm是一个分布式文件存储系统
net 获取节点信息
subscribe 订阅链上产生的新时间,包含logs,pendingTransactions,newBlockHeaders.syncing
ens 用于操作以太坊的域名服务
Iban 以太坊地址格式与IBAN(国际银行帐号) BBAN(基本银行账号)地址格式的转换

文章引用

  1. js-conflux-sdk 用户手册
  2. Web3 v1.2.11 用户手册
  3. Conflux JSONRPC介绍
  4. Conflux RPC与Ethereum RPC的区别