Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
您的应用程序不可避免地需要与“现实世界”API进行对话,例如是发送电子邮件,查询更多数据,或充当发起其他处理的信号。 下面让我们探讨如何让以太坊智能合约与脱链服务互通。
9 V6 p% x7 b, G4 r8 J8 o$ U8 U简而言之,您可以在处理事务时使智能合约发出事件。一旦事务被挖掘,事件数据就可以读取。在下图中,您可以看到您的DApp发出的事件可以从您的API的任何服务中检索。% i( C$ R% k4 B% P+ X3 w
. W- f. J# M+ P' k; u% ]0 h
目前有两种方法可以获取事件数据:
# w3 \. ]. G" [8 Y目前有两种方法可以获取事件数据:* X( O! L/ H% o+ C* A' a$ o' j, q5 E4 N
选项1:使用getTransactionReceipt7 R, ^# G5 p" N. J  u5 E$ U& y1 p0 ]
选项2:为事件注册监听器
% g! L, ?4 M9 j* E# G5 V您可以使用选项1来获取事件数据,但是可能会存在潜在问题,因为在区块被挖掘之前收据是空的。你可以提出调查,但这很难做到。
/ d5 i  A4 w+ D) V* a4 R. V另外,根据网络流量和gasPrice设置,交易可能长时间不会被打包。请注意,事件只有在被挖掘成区块后才会被传播。这意味着可以为任何一个区块调用多个事件。
* d. R$ m# i" {/ Wsolidity事件2 E1 p3 X/ l! h- J" p
在solidity里创建事件需要两个步骤:定义事件,发出事件。
4 d9 C' m% N8 z    pragma solidity ^0.4.18;
9 X! `9 H$ [: @1 bcontract MyContract {  / N/ U3 Q1 T; W* _% g0 n
event Transfer(address indexed from, address indexed to, uint256 value); /* This is an event */  + u9 F. \. q2 z3 T- J
function MyContract() {} /* a constructor */  : D$ O6 P, v! f" s/ c2 I2 i, R( s
function transfer(address _to) public {   ( Q* E- o& o8 z( [6 P+ o0 E
Transfer(msg.sender, _to, msg.value);  }}  3 G" s# J9 n3 K% f6 K* U7 [
注意事件Transfer是如何在第5行创建的,然后在函数传输中使用它发出Transfer事件(第10行)。 但会告诉你如何使用一个事件,如果我们用0x123调用传递函数,并从0x4444的地址发送1以太,则事件触发传输事件并应返回[0x4444,0x123,BigNumber(1以太)]。0 z6 q" Z& D, U2 r
监听事件/ u: _7 @5 U4 z
以太坊实现了他们的JSON RPC规范,但任何人都可以用他们选择的语言实现自己的库。 我们将使用Truffle和原始web3 Javascript API。 监听事件的一般流程如下:
! C/ }6 z% P0 O5 Y1 a7 n2 s; V1、加载合同组件/ N  X. |; U  ^8 S/ z6 _7 l
2、配置web3和使用truffle提供程序( ?: x; {' Z* C' X9 Z
3、识别网络id8 F8 g, `3 W! |2 H* f* t
4、从合同组件中获取正确的合同地址8 E, N$ {3 o) ?8 i( }7 T
5、获取JavaScript合约实例
3 N( L0 w0 k$ [0 Y" e; K6、使用可选配置调用contractInstace.NAME_OF_EVENT/ W- S4 k5 C4 \  f! N% j1 ^
下面我们有3个样本使用Truffle,Web3在1.0 beta之前,Web3在1.0 beta之后。$ a) r! r- d$ ?# F$ z0 z
Truffle API
" ~3 @$ f9 I+ e; QTruffle是web3的一个很好的包装器,它提供了一些便利功能,使用更加轻松。 看一下下面的代码示例:" X# H- d0 Y5 s6 D6 w. Q
const Web3 = require('web3') // Web3 0.20.4 or web3 1 beta  f6 T5 ~: i" Q7 U
const truffleContract = require("truffle-contract")
7 l# i1 `  h" F! Y9 f5 ?const contractArtifact = require('./build/contracts/TutorialToken.json')
5 y1 H4 [5 m5 }const providerUrl = 'http://localhost:8545'. Z& D8 L- I. c1 U2 k
const provider = new Web3.providers.HttpProvider(providerUrl)
1 K+ L! I. v/ c. \3 z' ~const contract = truffleContract(contractArtifact). g. g; }% k. i, {
contract.setProvider(provider)
" Y9 P1 I! A( O, |# H, K// dirty hack for web3@1.0.0 support for localhost testrpc, see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment3310845309 p; D9 ^* o% @0 n$ \
if (typeof contract.currentProvider.sendAsync !== "function") { : z9 d7 K0 C* K, e* \- \
contract.currentProvider.sendAsync = function() {      5 \( `( G5 D, N# O  S$ L; V
return contract.currentProvider.send.apply(      
1 N& b& a% g# J contract.currentProvider,           
) Q7 n: e/ w, V1 d arguments     + B' W1 Y* h9 A8 I& _& ]5 b
);   
' C% u/ v  Q/ d( e};  }
. [+ R; i2 `5 Acontract.deployed()  .then(contractInstance => {     e! ^3 v4 G7 `- f" O/ i' Q" c
const event = contractInstance.Transfer(null, {fromBlock: 0}, (err, res) => {   
0 }: C1 |, u& S( g7 c. [% M' Q3 s  if(err) {      " T4 n# o* _. _1 P' W1 r
  throw Error(err)     
7 k4 _& a5 d" k, `9 O0 D, v }    })   
( G- F" n! p% v- |! C3 M, | event.watch(function(error, result){      ) Q+ Y! ]( c+ [2 g0 L
if (error) { return console.log(error) }     6 K) A6 k- q% \8 L
if (!error) {      
6 Z1 o% {3 ^, R6 n' S( C // DO ALL YOUR WORK HERE!      
* i5 D3 \: n* _: C% H let { args: { from, to, value }, blockNumber } = result       2 g# z0 w( b! M$ j2 l* d
console.log(`----BlockNumber (${blockNumber})----`)        " I9 A  P3 l6 D& ]: q% d5 r
console.log(`from = ${from}`)       . P/ K/ F6 h6 v2 B
console.log(`to = ${to}`)       6 U) K3 F, z8 |7 u& a& _: n
console.log(`value = ${value}`)       9 g3 C, F* l- z" I$ r* p0 [
console.log(`----BlockNumber (${blockNumber})----`)   5 e$ ^9 F5 J/ ?; N! J$ ~
   }   
( Y! a5 _& e) q4 J })  }) 4 N; N3 m7 Q, l
.catch(e => {   . o6 G8 G- w" J6 y% V& ]9 m3 z; Y/ t
console.error('Catastrophic Error!')  2 e! g0 h  ?- x  G' m
  console.error(e) 4 ], z; }; _' M9 a( w$ r
})  4 L, ~! F& D7 W7 L. b
前9行需要一些模块,并设置truffle和web3能够正常网络通信。 第12-19行作为hack使其与web3一起使用,可以忽略。 工作从第21行开始,带有contract.deployed()。 这是一个很好的truffle辅助函数,可以从创建并保存到./build/contracts的工件中选择正确的合同地址。 返回contractInstance(第23行)后,我们通过调用contractInstance.NAME_OF_EVENT来“创建”该事件。 存在更多选项,可在此处找到。 我从0块中选择,因为它是我们自己的testrpc。 对于您的合同,最好选择更接近合同创建时的块编号。! k% V7 [6 M  @9 c' V7 H
Raw Web3(0.20.4及以下)* n( C0 x, v# K0 F" K
对于第二个示例,我们将直接使用Web3。 除了上一个示例中的hack之外,代码流程类似。/ i( \0 R0 C3 c
  const Web3 = require('web3') // Works with web3 0.20.4
. Q* t" f) J1 @: a) G' N6 y+ Econst contractArtifact = require('./build/contracts/TutorialToken.json')
8 Y% _1 O0 [# I; `7 g: gconst web3 = new Web3()
: D& @1 H  R6 D7 ^const providerUrl = 'http://localhost:8545'8 G6 S: E6 ^2 m5 m
const provider = new Web3.providers.HttpProvider(providerUrl)web3.setProvider(provider)
9 \' p) @9 P! Oconst networkId = web3.version.networkconst
. o! g* {7 c( ?( j- gcontractAddr = contractArtifact.networks[networkId].address# r- h  ?# @2 [  o; s$ V% N* o$ E& D
const TutorialToken = web3.eth.contract(contractArtifact.abi, contractAddr)- H6 E; I( x- ]1 |7 C3 b+ H
const contract = TutorialToken.at(contractAddr)
: B: y6 X- T7 J: p5 y2 ^8 Rconst event = contract.Transfer()! g3 a5 O/ m1 H! K- H
event.watch(function(error, result){   
- }3 G! H! V/ c, c; }5 F if (error) { return console.error(error) }    1 u$ S* Y$ [7 e- l9 C
  let { args: { from, to, value }, blockNumber } = result      1 g2 v! h7 b; L
console.log(`----BlockNumber (${blockNumber})----`)      
7 p4 k9 ~1 E, R. J  x6 Bconsole.log(`from = ${from}`)      
$ O& H7 J! r7 z3 Q' a' a/ gconsole.log(`to = ${to}`)      
& S" U: b& ]7 b) j! S1 iconsole.log(`value = ${value}`)      7 S& \" T7 i* w* @2 \
console.log(`----BlockNumber (${blockNumber})----`)  });  4 G1 B- ^& d2 g; o  J" h$ k
最重要的区别是第9-12行,我们手动从组件中抓取正确的网络。 我们没有很好的truffle.deployed功能来实现这一步。 现在我们在truffle示例中执行与之前相同的操作,并通过调用contract.NAME_OF_EVENT来创建事件。 在这个版本中我没有放一个块号,但是你可以传递与truffle版相同的东西。
# b/ T* q+ _4 }, ?( ~$ NRaw Web3 1.0.0 beta
' V0 C0 H& |% mWeb3确实为API带来了大量更改。 一个重大变化是我们必须使用webSockProvider来注册事件而不是httpProvider。
8 {) t; R, N3 g2 ^const Web3 = require('web3') // Works with web3 1.0.0-beta27
4 C5 W( L* I; ^# H& k, D6 kconst contractArtifact = require('./build/contracts/TutorialToken.json')
4 N* ^; c2 O/ F: x% U, K% E: {' Pconst web3 = new Web3()
2 h( D6 ?$ S( ]5 Oconst providerUrl = 'ws://localhost:8545' // requires # https://github.com/trufflesuite/ganache-cli/releases/tag/v7.0.0-beta.0 or https://github.com/trufflesuite/ganache/releases/tag/v1.1.0-beta.05 x  A* b; c3 Y( u) }& S( k7 Z+ w
const provider = new Web3.providers.WebsocketProvider(providerUrl)+ @2 Q3 z- g1 i4 }
web3.setProvider(provider)2 Y* Y0 i, `4 L% r: ~6 l$ K
web3.eth.net.getId()  .then(networkId => {   # R5 v; L! Z7 r* \0 W
const contractAddr = contractArtifact.networks[networkId].address    $ k3 ]" x$ F& |& S# X3 L
const TutorialToken = new web3.eth.Contract(contractArtifact.abi, contractAddr)    . h7 O1 b; ^1 E" n: ^& I2 y7 N7 v# @
TutorialToken.events.Transfer({fromBlock: 0},
5 g9 t+ {' `+ T; L% t2 Q5 _ function(error, event){ console.log(error) })      & x7 F6 `8 v/ r. e; u- n
.on('data', (log) => {       , ~3 u$ w+ Y3 d& }0 B8 ^# d
let {
! q5 I+ W/ H4 EreturnValues: { from, to, value }, blockNumber } = log    : @- _6 V5 }, i2 I7 b! k
    console.log(`----BlockNumber (${blockNumber})----`)        
& E  s6 M5 Z- e0 g# W% U7 yconsole.log(`from = ${from}`)      
, C, P8 @, G% _2 T5 u* y/ y  console.log(`to = ${to}`)       $ O8 F* E7 b" Q; j0 z  X& O/ m$ u
console.log(`value = ${value}`)        ! k1 i; I' Q$ \6 H
console.log(`----BlockNumber (${blockNumber})----`)     " ~) Z1 r; ]3 D
})      
7 p6 D5 _% W6 d0 z6 J.on('changed', (log) => {     % j$ N; j# |8 b
   console.log(`Changed: ${log}`)   
! }3 ]4 ^% R& ?$ |( c& W* v5 P7 I  })      .on('error', (log) => {   
1 v8 h; k# Z; {  N7 j- g' s     console.log(`error:  ${log}`)    # l$ i& B+ [* W# E1 S- x
  })  })  
' e& N  l9 U+ _+ g0 Z* C此外,获取networkId也已更新。 但过程是一样的。 我们使用web3.eth.net.getId()获取networkId,然后从Artifact中选择正确的合同地址。 初始化合同现在是一个类构造函数,在web3.eth.Contract中有一个大写C. 最后,我们创建了事件监听器。 我们现在必须自己处理“数据”,“更改”和“错误”事件。 之前它包含在前面2个示例中的watch功能中。$ K8 G) \) f. |5 L- n
总结
- S5 f  K4 ]( o0 v% Z# \: o您应该了解如何将您的offchain服务连接到onchain事件。 这意味着您现在可以将区块链集成到现有基础架构中。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

李悔之2015 初中生
  • 粉丝

    1

  • 关注

    0

  • 主题

    13