ewasm由于变化比较大,导致文章2018-11-26 ewasm在以太坊私有链测试
和2019-03-15 ewasm在以太坊私有链测试(2)已经无法成功发布和调用合约了,参考文章initial version of wrc20 token修改得到以下方法:
1、发布合约
先拉取代码,并按readme的方法操作
git clone https://github.com/hugo-dc/deploy-ewasm
cargo install chisel
cd deploy-ewasm\example
chisel run
能够获取store_deployer.wasm文件,然后执行:
cd ..
./sendtx.sh ./example/store_deployer.wasm 9 '8DFFB7687E432CF9540728F41579452F2F9B646DD29BBCA57B1AFE76817EC379'
Generating transaction...
Sending transaction...
0xf9012d09843b9aca00830f42408080b8dc0061736d0100000001090260027f7f0060000002130108657468657265756d0666696e697368000003030200010503010001071102046d61696e0002066d656d6f727902000a0e0202000b0900410041fe0010000b0b8401010041000b7e0061736d0100000001090260027f7f0060000002190108657468657265756d0c73746f7261676553746f72650000030201010503010001071102066d656d6f72790200046d61696e00010a0a0108004100412010000b0b26010041200b2000000000000000000000000000000000000000000000000000000000000000011ba055e580e1cdd74e63edac6114055b9293e2c2d32b1073e079152f6e9a69df039ea068fb6f81cce137032af8c716154866bc75b4b2b166ffacdd9c08a26f8f89b973
{"jsonrpc":"2.0","id":2,"error":{"code":-32000,"message":"intrinsic gas too low"}}
注:参数说明,参数9是nonce值,参数'8DFFB7687E432CF9540728F41579452F2F9B646DD29BBCA57B1AFE76817EC379'是当前发送交易的账户的私钥
出现了错误信息,"intrinsic gas too low"
修改文件txn.js
修改了txParams.gasLimit = gas
为:txParams.gasLimit = 1000000
再次执行:
./sendtx.sh ./example/store_deployer.wasm 9 '8DFFB7687E432CF9540728F41579452F2F9B646DD29BBCA57B1AFE76817EC379'
Generating transaction...
Sending transaction...
0xf9012d09843b9aca00830f42408080b8dc0061736d0100000001090260027f7f0060000002130108657468657265756d0666696e697368000003030200010503010001071102046d61696e0002066d656d6f727902000a0e0202000b0900410041fe0010000b0b8401010041000b7e0061736d0100000001090260027f7f0060000002190108657468657265756d0c73746f7261676553746f72650000030201010503010001071102066d656d6f72790200046d61696e00010a0a0108004100412010000b0b26010041200b2000000000000000000000000000000000000000000000000000000000000000011ba055e580e1cdd74e63edac6114055b9293e2c2d32b1073e079152f6e9a69df039ea068fb6f81cce137032af8c716154866bc75b4b2b166ffacdd9c08a26f8f89b973
{"jsonrpc":"2.0","id":2,"result":"0xda7a8778c5c2af8898a04995c200a347c2e000e985613b1c60e92c2accf6be88"}
这次成功了,查询交易0xda7a8778c5c2af8898a04995c200a347c2e000e985613b1c60e92c2accf6be88
可能还处于pending状态,需要等一段时间,这个网站好慢,然后可以看到| To: | New Contract (deployment address:0x7E729E5353C8AE3eD3Fe5669Ccd771A613acB17b) |
打开上面的连接,可以看到当前合约的wast代码,storage为空
2、调用合约
需要自己写个脚本和js
文件calltx.sh
#!/bin/bash
echo Generating transaction...
tx=$(node calltxn.js --nonce $1 --priv $2 --to $3)
echo Sending transaction...
echo $tx
curl -X POST -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"$tx\"],\"id\":2}" http://ewasm.ethereum.org:8545
文件calltxn.js
const EthereumTx = require('ethereumjs-tx')
var Web3 = require('web3')
var web3Provider = new Web3.providers.HttpProvider('http://ewasm.ethereum.org:8545')
var web3 = new Web3(web3Provider)
const argv = require('yargs').argv;
const fs = require('fs')
const request = require('request')
let data = ''
let nonce = argv.nonce ? argv.nonce : ''
let to = argv.to ? argv.to : ''
let priv = argv.priv
const privateKey = Buffer.from(priv, 'hex')
var txParams = {}
txParams.data = data
txParams.value = '0x0'
txParams.nonce = nonce
txParams.to = to
var gasPrice = 1000000000 // web3.eth.gasPrice
web3.eth.estimateGas(txParams, function(err, gas) {
txParams.gasLimit = 1000000
txParams.gasPrice = gasPrice
let tx = new EthereumTx(txParams)
tx.sign(privateKey)
let serializedTx = tx.serialize()
serializedTx = serializedTx.toString('hex')
console.log("0x"+serializedTx)
})
执行:
./calltx.sh 10 '8DFFB7687E432CF9540728F41579452F2F9B646DD29BBCA57B1AFE76817EC379' '0x7E729E5353C8AE3eD3Fe5669Ccd771A613acB17b'
注:参数说明:10是nonce,'8DFFB7687E432CF9540728F41579452F2F9B646DD29BBCA57B1AFE76817EC379' 是私钥,'0x7E729E5353C8AE3eD3Fe5669Ccd771A613acB17b'是合约地址
成功后查询交易0x9f6c8aed86b64c3a021685bfedc18a767dbd32a134cc4ddfd5649171234d5688
查询合约存储0x7E729E5353C8AE3eD3Fe5669Ccd771A613acB17b
可以看到storage中已经存储有值:
[
{
"key": "0x0000000000000000000000000000000000000000000000000000000000000000",
"value": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
]
3、使用自己的私有链测试
参考文章2018-11-26 ewasm在以太坊私有链测试启动私有链
修改sendtx.sh、txn.js、calltx.sh、calltxn.js中
http://ewasm.ethereum.org:8545
为
http://localhost:8545
启动go ethereum
./geth \
--vm.ewasm="./libhera.so,metering=true,fallback=true" \
--datadir ewasm-testnet-data \
--rpc --rpcapi "web3,net,eth,debug" \
--rpcvhosts="*" --rpcaddr "0.0.0.0" \
--rpccorsdomain "*" \
--nodiscover \
--networkid 66 \
--ipcpath geth1.ipc console
获取当前账户的私钥,参考2018-12-14 查看以太坊私钥
得到,
然后执行发布脚本:
./sendtx.sh ./example/store_deployer.wasm 1 '63fe0326d54575e4546bad24eb32776fcae08edbf9256b75ee7fcfed2b7d9822'
出现错误
{"jsonrpc":"2.0","id":2,"error":{"code":-32000,"message":"nonce too low"}}
在geth下查询当前nonce
eth.getTransactionCount('0xb338d763691dcfcff4720bc8f3e627901e239b30')
返回10
./sendtx.sh ./example/store_deployer.wasm 10 '63fe0326d54575e4546bad24eb32776fcae08edbf9256b75ee7fcfed2b7d9822'
返回正确:
{"jsonrpc":"2.0","id":2,"result":"0xff31a32577a67ff019ec686e245167adc39de8c18a85afd1f9131db49bcc7afa"}
开始挖矿
miner.start(1);admin.sleepBlocks(1);miner.stop();
在geth中查询
eth.getTransactionReceipt("0xff31a32577a67ff019ec686e245167adc39de8c18a85afd1f9131db49bcc7afa")
查询不到,但是日志信息中:
INFO [07-05|10:24:12.521] Submitted contract creation fullhash=0xff31a32577a67ff019ec686e245167adc39de8c18a85afd1f9131db49bcc7afa contract=0x9e14cE0f3B9AE6006E9E9039E336DB6196Ecb422
我们查询一下合约:
eth.getCode("0x9e14cE0f3B9AE6006E9E9039E336DB6196Ecb422")
也查询不到,
eth.getTransaction('0xff31a32577a67ff019ec686e245167adc39de8c18a85afd1f9131db49bcc7afa')
还在,使用
txpool.status
返回:
{
pending: 1,
queued: 0
}
发现还需要挖矿,继续
miner.start(1);admin.sleepBlocks(1);miner.stop();
这次总是可以查询到了,结论是必须挖矿两次,而不是一次
4、私有链下使用rpc测试
操作参考2019-03-14 通过rpc发布和调用以太坊合约
创建合约
{
"jsonrpc": "2.0",
"id": 171,
"method": "eth_sendTransaction",
"params": [
{
"data": "0x0061736d0100000001090260027f7f0060000002130108657468657265756d0666696e697368000003030200010503010001071102046d61696e0002066d656d6f727902000a0e0202000b0900410041fe0010000b0b8401010041000b7e0061736d0100000001090260027f7f0060000002190108657468657265756d0c73746f7261676553746f72650000030201010503010001071102066d656d6f72790200046d61696e00010a0a0108004100412010000b0b26010041200b200000000000000000000000000000000000000000000000000000000000000001",
"from": "0xb338d763691dcfcff4720bc8f3e627901e239b30",
"gas": "0x47b760"
}
]
}
获得结果
{
"jsonrpc": "2.0",
"id": 171,
"result": "0xcce335377ff76cfa135c88fbc6b337539f03e7808f77473095a670104c3c8929"
}
如果出现"authentication needed: password or unlock",需要解锁
personal.unlockAccount("0xb338d763691dcfcff4720bc8f3e627901e239b30")
上面data中的数据可以通过wasm2hex.js获取,其内容
var fs=require('fs');
var path=require('path');
var args = process.argv.splice(2)
var file=path.resolve(args[0]);
var content=Buffer.alloc(0);//累计合并读取片段
fs.readFile(file,function(err,chunk){
if(err)
return console.error(err);
console.log(chunk);
//将数据转换为hex字符串
console.log(chunk.toString('hex'));
//合并Buffer
content=Buffer.concat([content,chunk]);
//保存成文件
var imgData=Buffer.from(content);
fs.writeFile(path.resolve('test.txt'),imgData.toString('hex'),function(err){
if(err)
return console.error(err);
});
});
执行:
node wasm2hex.js store_deployer.wasm
从生成的文件test.txt复制,记得data前缀是0x,否则出现错误:"invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go struct field SendTxArgs.data of type hexutil.Bytes"
同样的问题,我们需要挖矿两次,才能正确获得交易结果
miner.start(1);admin.sleepBlocks(1);miner.stop();
miner.start(1);admin.sleepBlocks(1);miner.stop();
获得交易结果:
{
"jsonrpc": "2.0",
"id": 2192787296,
"method": "eth_getTransactionReceipt",
"params": [
"0xcce335377ff76cfa135c88fbc6b337539f03e7808f77473095a670104c3c8929"
]
}
返回:
{
"jsonrpc": "2.0",
"id": 2192787296,
"result": {
"blockHash": "0x8ef493560a75fcab08a04fc0dd2a903daa53952912e57bf1fe746361d05f4df5",
"blockNumber": "0x136",
"contractAddress": "0xfbd68b1fffd21ba3112583383c4b51d9f8a6e4ff",
"cumulativeGasUsed": "0x16f7c",
"from": "0xb338d763691dcfcff4720bc8f3e627901e239b30",
"gasUsed": "0x16f7c",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": null,
"transactionHash": "0xcce335377ff76cfa135c88fbc6b337539f03e7808f77473095a670104c3c8929",
"transactionIndex": "0x0"
}
}
获得合约地址:0xfbd68b1fffd21ba3112583383c4b51d9f8a6e4ff
调用合约:
{
"jsonrpc": "2.0",
"id": 171,
"method": "eth_sendTransaction",
"params": [
{
"data": "0x",
"from": "0xb338d763691dcfcff4720bc8f3e627901e239b30",
"to": "0xfbd68b1fffd21ba3112583383c4b51d9f8a6e4ff",
"gas": "0x47b760"
}
]
}
返回:
{
"jsonrpc": "2.0",
"id": 171,
"result": "0xd7452ccafbff75e5653213f5324137c90d5b74acd683e193eb5a756a90e8dd79"
}
执行一次挖矿
miner.start(1);admin.sleepBlocks(1);miner.stop();
查询合约存储信息
{
"jsonrpc": "2.0",
"id": 1115,
"method": "eth_getStorageAt",
"params": [
"0xfbd68b1fffd21ba3112583383c4b51d9f8a6e4ff",
"0x0",
"latest"
]
}
返回
{
"jsonrpc": "2.0",
"id": 1115,
"result": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
完全正确
5、使用包装前的wasm测试
采用4的方法,对包装前的store.wasm测试了发布和调用,都是成功的,因此不理解为啥deploy-ewasm强调wasm需要通过chisel run处理wasm文件
找到原因了,chisel run处理后的合约发布后,保存到链上的是chisel run处理前的合约,这样就可以保证合约在发布的时候不会被执行,只有调用的时候才能够执行,另外也是通过这个包装确保了合约在发布的时候可以调用哨兵合约进行检查。
但是这块也是个漏洞,因为不使用chisel run处理wasm文件,就发布合约,会规避了哨兵合约的检查。