如何订阅“日志事件”并在 ThunderCore 上获取通知?
Posted
技术标签:
【中文标题】如何订阅“日志事件”并在 ThunderCore 上获取通知?【英文标题】:How do I subscribe to `log events` and get notifications on ThunderCore? 【发布时间】:2020-08-31 21:10:34 【问题描述】:我想订阅log
事件并在 ThunderCore 上接收通知时遇到一些问题。
据我所知,我似乎应该使用 websocket 和eth_subscribe
。有例子吗??
或者,是否有其他解决方案可以实现我的目标?
【问题讨论】:
【参考方案1】:通过以下方式获取有关 ThunderCore 上新合约事件的通知:
-
使用 Websocket 连接到 RPC 节点,例如,https://testnet-rpc.thundercore.com
在
logs
事件上调用eth_subscribe
RPC 方法
独立示例
SimpleRecord.sol
pragma solidity ^0.4.25;
contract SimpleRecord
event Record(
address indexed _from,
uint _value
);
function write() payable public
emit Record(msg.sender, msg.value);
要生成Record
事件,请运行simple-record-write
以查看运行simple-record-log-subscribe
的通知:
const process = require('process')
const path = require('path')
const fs = require('fs')
const Web3 = require('web3')
const Accounts = require('web3-eth-accounts')
const util = require('util')
// truffle migrate --reset --network thunder-mainnet
const thunderWsUrl = 'wss://mainnet-ws.thundercore.com'
// truffle migrate --reset --network thunder-testnet
//const thunderWsUrl = 'wss://testnet-ws.thundercore.com'
const programName = () =>
return path.basename(process.argv[1])
const web3Url = () =>
let u = process.env['WEB3_PROVIDER_URI']
if (u === undefined)
u = thunderWsUrl
return u
const signTx = async (fromAccount, tx) =>
const signedTx = await fromAccount.signTransaction(tx)
return signedTx.rawTransaction // hex string
const setup = async () =>
const privateKeys = fs.readFileSync(path.join(__dirname, '..', '.private-keys'), encoding: 'ascii').split('\n').filter(x => x.length > 0)
const accounts = new Accounts()
const account = accounts.privateKeyToAccount('0x' + privateKeys[0])
const jsonBuf = fs.readFileSync(path.join(__dirname, '..', 'build', 'contracts', 'SimpleRecord.json'))
const contractData = JSON.parse(jsonBuf)
const contractAbi = contractData['abi']
const web3ProviderUrl = web3Url()
const web3 = new Web3(web3ProviderUrl)
const networkId = await web3.eth.net.getId()
let deployedNetwork, contractAddress
try
deployedNetwork = contractData['networks'][networkId]
contractAddress = deployedNetwork['address']
catch (err)
msg = `error getting deployedNetwork: $err`
throw new Error(msg)
const contract = new web3.eth.Contract(contractAbi, contractAddress)
return [ web3ProviderUrl, web3, networkId, contractAddress, contract, account ]
const prettyPrint = (o) =>
return util.inspect(o, showHidden: false, depth: null, colors: true)
const recordWrite = async () =>
const [web3ProviderUrl, web3, chainId, contractAddress, contract, fromAccount] = await setup()
console.log('web3ProviderUrl:', web3ProviderUrl)
const txnData = contract.methods.write().encodeABI()
console.log('account.address:', fromAccount.address)
const promiseResults = await Promise.all([
web3.eth.getTransactionCount(fromAccount.address),
web3.eth.getGasPrice(),
])
const nonce = promiseResults[0]
const gasPrice = promiseResults[1]
const tx =
'gasLimit': 0,
'chainId': chainId,
'gasPrice': gasPrice,
'nonce': Web3.utils.toHex(nonce),
'from': fromAccount.address,
'to': contractAddress,
'value': 0xbeef,
'data': txnData,
const gasMultiple = 2.0
tx.gasLimit = (await web3.eth.estimateGas(tx)) * gasMultiple
console.log('tx:', prettyPrint(tx))
const rawTxStr = await signTx(fromAccount, tx)
const r = await web3.eth.sendSignedTransaction(rawTxStr)
console.log('sendTransaction: receipt:', prettyPrint(r))
return 0
const logSubscribe = () =>
return new Promise((resolve, reject) =>
setup().then(([web3ProviderUrl, web3, chainId, contractAddress, contract, account]) =>
let eventCount = 0
console.log('web3ProviderUrl:', web3ProviderUrl)
console.log('contractAddress:', contractAddress)
console.log('contract.options.jsonInterface:', prettyPrint(contract.options.jsonInterface))
const eventAbis = contract.options.jsonInterface.filter((abiObj) => abiObj.type === 'event')
web3.eth.subscribe('logs', address: contractAddress , (err, log) =>
console.log('eth.subscribe("logs") callback')
if (err)
console.log('logs callback, err:', err)
reject(err)
return
eventCount++
console.log(`log[$eventCount]:`, log)
const eventSig = log.topics[0]
for (let abi of eventAbis)
if (eventSig === abi.signature)
const decoded = web3.eth.abi.decodeLog(abi.inputs, log.data, log.topics.slice(1))
console.log('Decoded Event:', prettyPrint(abi), '\n', prettyPrint(decoded))
resolve(0)
return
)
)
)
(async () =>
if (programName().endsWith('-write'))
process.exit(await recordWrite())
else if (programName().endsWith('-log-subscribe'))
process.exit(await logSubscribe())
else
console.error(`unsupported program name: "$programName()"`)
process.exit(2)
)()
在field-support
repo 的subscribe-to-logs
分支中查看完整的项目here。
【讨论】:
【参考方案2】:listen_to_thundercore_mainnet.js
/**
* Connect to Thundercore mainnet and listen for tips to a specific smart contract address.
*/
const Web3 = require('web3');
var provider = 'wss://mainnet-ws.thundercore.com';
var web3 = new Web3(provider);
let listenOnce = () =>
// Create a connection to Thundercore mainet.
const smartContractAddress = '0xb7d82e5B73e01bB4c1cFB1448f1215bf165929a2'
var subscription = web3.eth.subscribe('logs',
address: smartContractAddress,
, (error, result) =>
if (error)
console.log(error)
console.log('Reconnecting to Thundercore mainnet.')
setTimeout( () =>
// Re-instantiating web3 is needed in case the connection is dropped.
web3 = new Web3(provider);
_listen()
, 5000);
)
.on('connected', (subscriptionId) =>
console.log('connected')
)
.on('data', (log) =>
console.log(log);
)
.on("changed", (log) =>
console.log('changed')
)
return subscription
const _listen = async () =>
let tips = listenOnce();
console.log('Connected to Thundercore mainnet.')
// web3 subscription times out at 60 secs. Close and reopen at 50 secs.
setInterval( () =>
tips.unsubscribe( (error, success) =>
if(error)
console.log('Failed to disconnect from Thundercore mainnet!');
if(success)
console.log('disconnected');
);
tips = listenOnce();
, (50 * 1000));
_listen()
使用 NodeJS 运行
node listen_to_thundercore_mainnet.js
Thundercore 会在 60 秒后断开您的连接。所以我们在此之前故意断开连接并立即重新连接。 这种方式在跟踪流量大的合约时会漏掉一些交易。
【讨论】:
以上是关于如何订阅“日志事件”并在 ThunderCore 上获取通知?的主要内容,如果未能解决你的问题,请参考以下文章
如何仅在输入模糊时触发反应表单 valueChanges 订阅并在 Angular 2 中输入键
如何制作响应 ubuntu 14.04 和 16.04 上的 syslog 事件的 c# 程序?