在做去区块链数字钱包,交易所等产品的时候,任何涉及到区块链交易的场合,都需要结合共识算法来考虑交易确认数的问题.
交易确认数的获取:
1.提交交易,得到交易哈希
2.定时获取当前区块高度,并使用交易哈希获取交易所在区块高度,两者相减,得到确认数
一般来说,发生跨主体资产转移的交易,最好都进行确认数监控。常见的场景是从第三方接收一笔转账
比特币是 6 个确认,以太坊是 12 个确认,EOS 是 15 个确认。
项目实战:比特币充提款集成
一.Bitcoin
1.查询交易
gettransaction是定义在src/wallet/rpcwallet.cpp中的rpc接口,只能查钱包内的交易.钱包交易使用
txid.
1.1* CreateRawTransaction:创建一个消耗给定输入并创建新输出的交易。
或 SendRawTransaction:将[原始交易](https://bitcoin.org/en/glossary/serialized-transaction "Complete transactions in their binary format; often represented using hexadecimal. Sometimes called raw format because of the various Bitcoin Core commands with "raw" in their names.")(序列化,十六进制编码)提交给本地节点和网络
1.2 decoderawtransaction
RPC返回表示序列化,十六进制编码的交易JSON对象 .产生txid
getrawtransaction是src/rpc/rawtransaction.cpp中的rpc接口,默认是只查询交易池中的交易,但是如果开启了-txindex 选项,则也会查询区块链中的交易
2.如何查询一个地址的所有交易(https://blog.csdn.net/shebao3333/article/details/89552252 )
1、将比特币交易数据存入数据库
由于比特币的数据存储结构,不可能直接利用比特币的原始API来查询指定地址的历史交易数据。因此最朴素(Naive)的第一种解决方案,就是将比特币区块链上的每一笔交易数据存到自己的数据库里,然后针对交易地址信息(例如Scriptpubkey、pubkey或者地址本身)建立索引,这样就可以在数据库上自由、高效地查询了。
2、利用第三方的服务
朴素的第一种方案需要自己解析比特币区块链数据,自己搭建数据库环境,可能你觉得有点麻烦。好在有很多第三方机构已经做了这件繁琐的事情,并且通过开放API的形式提供出来,你可以直接使。
例如,你可以使用blockchain.info的api来实现这个功能:
$ curl https://blockchain.info/rawaddr/$bitcoin_address
无需注册
(https://www.blockchain.com/zh-cn/api/q/addressbalance/1EzwoHtiXB4iFwedPr49iywjZn2nnekhoj?confirmations=6)需要注册
3、换一种比特币节点实现软件
如果你不愿意自己搞数据库,也不愿意使用第三方的开放API,还有第三种解决方案,就是换一种支持按比特币地址查询交易的节点实现软件,例如btcd,这是一个go语言实现的比特币节点软件,当你启动btcd时,只要使用--addrindex标志就可以自动建立比特币地址索引了:
$ btcd --addrindex
3.Tokenview API 获取加密货币交易确认数(https://tokenview.com/cn/api)
GET http://www.tokenview.com:8088/tx/confirmation/{coin}/{txid}
参数说明
{coin} : 请求类型为String - 币种简称[ETH,ETC,BTC,BCH,DOGE,DASH,ZCASH,LTC]
{txid} : 请求类型为String - 例如2798f70cb126ed98f726749fa7632499072ba6a3561c11f3103151bf5b884f68
二.web3
以太坊常用命令总结(https://blog.csdn.net/weixin_33770878/article/details/87546979)
1.web3.eth.getTransaction(transactionHash [, callback])(https://blog.csdn.net/shebao3333/article/details/80078160 )
返回匹配指定交易哈希值的交易
参数:
transactionHash: String - 交易的哈希值。
callback: Function - 回调函数,用于支持异步的方式执行7。
返回值:
Object - 一个交易对象
hash: String - 32字节,交易的哈希值。
nonce: Number - 交易的发起者在之前进行过的交易数量。
blockHash: String - 32字节。交易所在区块的哈希值。当这个区块处于pending将会返回null。
blockNumber: Number - 交易所在区块的块号。当这个区块处于pending将会返回null。
transactionIndex: Number - 整数。交易在区块中的序号。当这个区块处于pending将会返回null。
from: String - 20字节,交易发起者的地址。
to: String - 20字节,交易接收者的地址。当这个区块处于pending将会返回null。
value: BigNumber - 交易附带的货币量,单位为Wei。
gasPrice: BigNumber - 交易发起者配置的gas价格,单位是wei。
gas: Number - 交易发起者提供的gas。.
input: String - 交易附带的数据。
var blockNumber = 668;
var indexOfTransaction = 0
var transaction = web3.eth.getTransaction(blockNumber, indexOfTransaction);
console.log(transaction)
{
"hash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b",
"nonce": 2,
"blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
"blockNumber": 3,
"transactionIndex": 0,
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"value": BigNumber,
"gas": 314159,
"gasPrice": BigNumber,
"input": "0x57cb2fc4"
}
2.web3.eth.getTransactionReceipt
web3.eth.getTransactionReceipt()方法返回指定交易的收据对象。 如果交易处于pending状态,则返回null。
调用:
web3.eth.getTransactionReceipt(hash [, callback])
参数:
hash:String - 交易的哈希值
callback:Function - 可选的回调函数,其第一个参数为错误对象,第二个参数为结果
返回值:
一个Promise对象,其解析值为交易的收据对象或者null。收据对象具有如下字段:
status - Boolean: 成功的交易返回true,如果EVM回滚了该交易则返回false
blockHash 32 Bytes - String: 交易所在块的哈希值
blockNumber - Number: 交易所在块的编号
transactionHash 32 Bytes - String: 交易的哈希值
transactionIndex - Number: 交易在块中的索引位置
from - String: 交易发送方的地址
to - String: 交易接收方的地址,对于创建合约的交易,该值为null
contractAddress - String: 对于创建合约的交易,该值为创建的合约地址,否则为null
cumulativeGasUsed - Number: 该交易执行时所在块的gas累计总用量
gasUsed- Number: 该交易的gas总量
logs - Array: 该交易产生的日志对象数组
示例代码:
var receipt = web3.eth.getTransactionReceipt('0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b') .then(console.log);
{
"status": true,
"transactionHash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b",
"transactionIndex": 0,
"blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
"blockNumber": 3,
"contractAddress": "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",
"cumulativeGasUsed": 314159,
"gasUsed": 30234,
"logs": [{
// logs as returned by getPastLogs, etc.
}, ...]
}
3.web3.eth.getGasPrice
web3.eth.getGasPrice()方法用来获取当前gas价格,该价格由最近的若干块 的gas价格中值决定。
调用:
web3.eth.getGasPrice([callback])
返回值:
一个Promise对象,其解析值为表示当前gas价格的字符串,单位为wei。
示例代码:
web3.eth.getGasPrice().then(console.log);
"20000000000"
4.验证交易是否成功(https://blog.csdn.net/DDFFR/article/details/74908579)
一般是通过event来查看的
event mylog(uint code);
function test()
{
…
mylog(0);
}
发起交易后,根据eth.getTransactionReceipt()检索,结果大致如下
{
“jsonrpc”:“2.0”,
“id”:1,
“result”:{
“blockHash”:“0xde5d1584b86db40a4ea64b8474f7b6d2c693f18ead347202f3c03a0d9904c672”,
“blockNumber”:“0x186f”,
“contractAddress”:null,
“cumulativeGasUsed”:“0x92e79”,
“from”:“0xe5684e632668d1bf0a84a60d98b3e7230695f568”,
“gasUsed”:“0x10531”,
“logs”:[
{
“address”:“0xee1b3f3a4e5f2b2d3029b6b65f3684e73b437447”,
“blockHash”:“0xde5d1584b86db40a4ea64b8474f7b6d2c693f18ead347202f3c03a0d9904c672”,
“blockNumber”:“0x186f”,
“data”:“0x0000000000000000000000000000000000000000000000000000000000000000”,
“logIndex”:“0x8”,
“topics”:[],
“transactionHash”:“0x58a16df942e3fb4f7d3476c9c8af05b95368960eb43cafdb9c3ecac1c4e0d59a”,
“transactionIndex”:“0x0”
}
],
“root”:“be061b18e7f402e4f1348e345316101c2939967ea5276564e0a698bc63c07de0”,
“to”:“0xee1b3f3a4e5f2b2d3029b6b65f3684e73b437447”,
“transactionHash”:“0x58a16df942e3fb4f7d3476c9c8af05b95368960eb43cafdb9c3ecac1c4e0d59a”,
“transactionIndex”:“0x8”
}
}
如果返回结果中log节点不为空,且data的值为0,则说明合约中的test函数执行成功了。
5.以太坊中查询某个地址的交易记录(https://blog.csdn.net/weixin_33717117/article/details/88233439 )
以太坊提供了查询某个block中包含的Transactions,以及根据交易hash来获取Transaction的方法。但是以太坊并没有提供直接根据一个Address查询对应交易记录的方法。那么我们有三种方法可以来查询。
5.1.利用循环的方式,查询某一个block区间中,包含的与该地址相关的交易。
5.2.利用 filter监听交易,当出现与该地址相关的交易时,存储到数据库中,需要查询的时候直接从本地数据库中查询。但是这个可能会遇到一个问题,就是假如某一个时刻,服务中断或出现异常,那么可能这一条数据就丢失了。https://docs.web3j.io/getting_started.html#gradle
var addr = "0xbfb2e296d9cf3e593e79981235aed29ab9984c0f"
var filter = web3.eth.filter({fromBlock:0, toBlock:'latest', address: addr});
filter.get(function (err, transactions) {
transactions.forEach(function (tx) {
var txInfo = web3.eth.getTransaction(tx.transactionHash);
//这时可以将交易信息txInfo存入数据库
});
});
5.3.启动一个Job,用Job来遍历数据,把数据插入到本地数据库中
根据地址查询交易
下面是第一种方法的web3.js实现,利用循环的方式,查询某一个block区间中,包含的与该地址相关的交易。代码如下:
var Web3 = require("web3");
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
getTransactionsByAddr(web3,"0x6e4Cc3e76765bdc711cc7b5CbfC5bBFe473B192E",133064,134230);
//myaccount :需要查询的地址信息,startBlockNumber:查询的其实blockNumber,endBlockNumber:查询的结束blockNumber
async function getTransactionsByAddr(web3,myaccount,startBlockNumber,endBlockNumber) {
if (endBlockNumber == null) {
endBlockNumber = await web3.eth.blockNumber;
console.log("Using endBlockNumber: " + endBlockNumber);
}
if (startBlockNumber == null) {
startBlockNumber = endBlockNumber - 1000;
console.log("Using startBlockNumber: " + startBlockNumber);
}
console.log("Searching for transactions to/from account \"" + myaccount + "\" within blocks " + startBlockNumber + " and " + endBlockNumber);
for (var i = startBlockNumber; i <= endBlockNumber; i++) {
if (i % 1000 == 0) {
console.log("Searching block " + i);
}
var block = await web3.eth.getBlock(i, true);
if (block != null && block.transactions != null) {
block.transactions.forEach(function (e) {
if (myaccount == "*" || myaccount == e.from || myaccount == e.to) {
console.log(" tx hash : " + e.hash + "\n"
+ " nonce : " + e.nonce + "\n"
+ " blockHash : " + e.blockHash + "\n"
+ " blockNumber : " + e.blockNumber + "\n"
+ " transactionIndex: " + e.transactionIndex + "\n"
+ " from : " + e.from + "\n"
+ " to : " + e.to + "\n"
+ " value : " + web3.utils.fromWei(e.value.toString()) + "\n"
+ " time : " + timeConverter(block.timestamp) + " " + new Date(block.timestamp * 1000).toGMTString() + "\n"
+ " gasPrice : " + e.gasPrice + "\n"
+ " gas : " + e.gas + "\n"
+ " input : " + e.input
+ "--------------------------------------------------------------------------------------------"
);
}
})
}
}
}
function timeConverter(UNIX_timestamp) {
var a = new Date(UNIX_timestamp * 1000);
var year = a.getFullYear();
var month = a.getMonth() + 1;
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = year + '/' + month + '/' + date + ' ' + hour + ':' + min + ':' + sec;
return time;
}
5.4 etherscan API查询(https://blog.csdn.net/weixin_34211761/article/details/86946122 )
http://api.etherscan.io/api?module=account&action=txlist&address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae&startblock=0&endblock=99999999&sort=asc&apikey=YourApiKeyToken
只能返回最近的1000条交易信息
或者
https://api.etherscan.io/api?module=account&action=txlist&address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae&startblock=0&endblock=99999999&page=1&offset=10&sort=asc&apikey=YourApiKeyToken
这种方式返回指定个数的交易信息
注意:
1、module、action、module、sort都是固定值。
2、startblock和endblock是指查询2个区块区间的所有指定地址交易,通常startblock为0,endblock设置为"latest"即可。
3、apikey需要申请,apikey 是在etherscan调用那些接口都需要用到的一个参数,它是需要你去申请的,注册账号之后就能得到。每个账户最多持有 3 个 token, 请求 API service 服务, 仅需其中一个即可。
4.测试环境https://api-ropsten.etherscan.io
以太坊go-ethereum客户端查询交易列表探讨
6.以太坊交易确认数如何获取https://blog.csdn.net/mongo_node/article/details/86056734
async function getTxConfirms(txhash){
const receipt = await web3.eth.getTransactionReceipt(txhash)
//later...
const latest = await web3.eth.getBlockNumber()
//confirms
return latest - receipt.number + 1
}
getTxConfirms('0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b')
.then(confirms => console.log(confirms))