Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
您的应用程序不可避免地需要与“现实世界”API进行对话,例如是发送电子邮件,查询更多数据,或充当发起其他处理的信号。 下面让我们探讨如何让以太坊智能合约与脱链服务互通。* G* Y+ i: m$ r1 k: ^0 n
简而言之,您可以在处理事务时使智能合约发出事件。一旦事务被挖掘,事件数据就可以读取。在下图中,您可以看到您的DApp发出的事件可以从您的API的任何服务中检索。. x- [0 M2 Y' M! |# V5 m& m' J* e

- T5 p/ r8 G9 L! L& }3 f2 x* m( Q目前有两种方法可以获取事件数据:- L5 C4 @! b) n) f
目前有两种方法可以获取事件数据:
4 j" ]% c& L6 T" E: ]选项1:使用getTransactionReceipt- ?0 P, f, u$ _* j% [' p0 ]/ J
选项2:为事件注册监听器3 _% T( L3 E5 p# v
您可以使用选项1来获取事件数据,但是可能会存在潜在问题,因为在区块被挖掘之前收据是空的。你可以提出调查,但这很难做到。
5 p, w2 F/ O) E" U另外,根据网络流量和gasPrice设置,交易可能长时间不会被打包。请注意,事件只有在被挖掘成区块后才会被传播。这意味着可以为任何一个区块调用多个事件。. L1 x) f8 L4 ~5 n, w
solidity事件2 d- F3 X5 `1 V5 {+ Y
在solidity里创建事件需要两个步骤:定义事件,发出事件。
4 d& X. d8 ?+ V% J" G  w8 B9 T    pragma solidity ^0.4.18;+ S0 n$ J6 {6 s2 }# _/ O2 S# p
contract MyContract {  
* r1 J5 t; X# g2 u+ V. s9 [event Transfer(address indexed from, address indexed to, uint256 value); /* This is an event */  
+ V& E2 A- i/ f! Dfunction MyContract() {} /* a constructor */  , s. E% J, Z( P1 z/ d6 a1 q' \
function transfer(address _to) public {   
' D( }5 A/ W. o- @ Transfer(msg.sender, _to, msg.value);  }}  
# ]/ H. o+ p8 ]注意事件Transfer是如何在第5行创建的,然后在函数传输中使用它发出Transfer事件(第10行)。 但会告诉你如何使用一个事件,如果我们用0x123调用传递函数,并从0x4444的地址发送1以太,则事件触发传输事件并应返回[0x4444,0x123,BigNumber(1以太)]。9 c& D' D$ C5 t
监听事件1 [/ f9 @4 q2 I8 f( P# m2 [
以太坊实现了他们的JSON RPC规范,但任何人都可以用他们选择的语言实现自己的库。 我们将使用Truffle和原始web3 Javascript API。 监听事件的一般流程如下:
( t3 L' }: S( z7 r9 J7 j1、加载合同组件
% B, ^5 b( N' v. I# J2、配置web3和使用truffle提供程序
, s5 D1 T9 A3 |! m! K3、识别网络id* I, I) B6 o" g9 a* V. n: I, V
4、从合同组件中获取正确的合同地址
& E  o3 t+ L/ D# e5、获取JavaScript合约实例: y6 K: o4 j% z& n# W& T
6、使用可选配置调用contractInstace.NAME_OF_EVENT) i$ J4 R7 S  z- m4 _  _4 V% ~6 H
下面我们有3个样本使用Truffle,Web3在1.0 beta之前,Web3在1.0 beta之后。( o9 x! j/ H4 n* l4 y2 ~' s) q
Truffle API
, o* C- V. Y0 @3 G2 W4 Y. y; pTruffle是web3的一个很好的包装器,它提供了一些便利功能,使用更加轻松。 看一下下面的代码示例:
4 w. G+ K9 e: B8 C6 ^const Web3 = require('web3') // Web3 0.20.4 or web3 1 beta
9 c, c3 T7 L& F  mconst truffleContract = require("truffle-contract")( I" A3 u0 c- H! R0 P
const contractArtifact = require('./build/contracts/TutorialToken.json')
& A4 q/ P* Y4 D5 z3 _. Gconst providerUrl = 'http://localhost:8545'
) J6 I6 E" A! O% t; Q! u) ~; fconst provider = new Web3.providers.HttpProvider(providerUrl)3 k$ v2 W& N. i4 z/ k4 \
const contract = truffleContract(contractArtifact)1 i0 X0 n1 s3 Z. n! {' x
contract.setProvider(provider); q+ O. F7 L/ |* B' Q0 s6 d
// dirty hack for web3@1.0.0 support for localhost testrpc, see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment331084530
5 ], C' h) e- B* uif (typeof contract.currentProvider.sendAsync !== "function") {
0 Q- o. M- D( s7 G contract.currentProvider.sendAsync = function() {      
% \8 P; P7 N0 x8 b% q4 E# Z7 L7 ereturn contract.currentProvider.send.apply(      
  W% n' y8 U+ N contract.currentProvider,           
; t. H  C5 K  d3 d2 J arguments     
( ^: }$ W; V. u% w9 \8 G( l9 y0 K );   
+ P# k: p) W. q6 H# H};  }
: r1 Q2 M1 W6 Z  G- Rcontract.deployed()  .then(contractInstance => {   * C5 X3 x) I. p' |: [' \8 g
const event = contractInstance.Transfer(null, {fromBlock: 0}, (err, res) => {    3 A/ _9 g) l. O& E
  if(err) {      
- y) E' j4 ~! h% s$ k  throw Error(err)     6 x& ?7 U3 S8 t* H0 H
}    })   
3 z  U+ p* k' ]* }" A& f event.watch(function(error, result){      1 Y' k+ f0 c- [" h' p, O
if (error) { return console.log(error) }     4 L! W  w5 R' S& u
if (!error) {      
& Y! y0 m0 J. x% R! G. }, d // DO ALL YOUR WORK HERE!       7 {) L5 W) ]1 S6 ?# H5 f
let { args: { from, to, value }, blockNumber } = result      
# e) u/ V( G% ]1 k+ y console.log(`----BlockNumber (${blockNumber})----`)        
6 G7 z, r  a% u$ z% lconsole.log(`from = ${from}`)      
0 ]+ Q- D% X/ V' R console.log(`to = ${to}`)      
% m' Q" X4 O3 ^ console.log(`value = ${value}`)      
5 c. }5 G" w! U console.log(`----BlockNumber (${blockNumber})----`)   : D  `' p( `  X- q) W
   }   2 b1 r+ y- R6 {. }6 J( m4 _& ?
})  }) ) T5 u) v1 s" _7 u3 c
.catch(e => {   
" g% ~0 N& W0 }# P4 ?" e- T0 B console.error('Catastrophic Error!')  
0 ]( l/ S9 U* V8 h8 f0 L" i' {- q  console.error(e)
! z" C! _/ M' k) N- B$ Q$ m })  5 B; E0 r! I" e9 O/ S
前9行需要一些模块,并设置truffle和web3能够正常网络通信。 第12-19行作为hack使其与web3一起使用,可以忽略。 工作从第21行开始,带有contract.deployed()。 这是一个很好的truffle辅助函数,可以从创建并保存到./build/contracts的工件中选择正确的合同地址。 返回contractInstance(第23行)后,我们通过调用contractInstance.NAME_OF_EVENT来“创建”该事件。 存在更多选项,可在此处找到。 我从0块中选择,因为它是我们自己的testrpc。 对于您的合同,最好选择更接近合同创建时的块编号。
) t0 ^% K8 i! W4 vRaw Web3(0.20.4及以下)
& W! b: ]  f3 s# \/ h( A+ @# N对于第二个示例,我们将直接使用Web3。 除了上一个示例中的hack之外,代码流程类似。4 f3 o5 q" x/ {6 g4 u, w. r9 w1 E' R
  const Web3 = require('web3') // Works with web3 0.20.4
( p8 k& D( c5 a  j! F% e8 C% Yconst contractArtifact = require('./build/contracts/TutorialToken.json')
+ X8 p2 H" R4 K. [1 ]0 ]const web3 = new Web3()
6 {+ j3 X5 e( G9 _: Zconst providerUrl = 'http://localhost:8545'
- C! U$ I4 A/ h1 x3 p' r% Gconst provider = new Web3.providers.HttpProvider(providerUrl)web3.setProvider(provider)
8 Z; m6 t0 E2 Y: Cconst networkId = web3.version.networkconst
2 g4 L* f* b% t% C6 d5 BcontractAddr = contractArtifact.networks[networkId].address7 v* U  U- l4 E8 H
const TutorialToken = web3.eth.contract(contractArtifact.abi, contractAddr)/ I2 c  f' L% b1 {1 f) F
const contract = TutorialToken.at(contractAddr)
% t0 r  N3 I* K: l! U* X7 }const event = contract.Transfer()/ ~( i$ l7 M7 u
event.watch(function(error, result){   % V2 R4 |9 d- \: d5 h# e2 g, D1 p& g
if (error) { return console.error(error) }    / O, g2 u% h: C. @) _& u
  let { args: { from, to, value }, blockNumber } = result      
, c4 U5 e0 L4 r# x2 U0 qconsole.log(`----BlockNumber (${blockNumber})----`)      
; X7 O) L4 U2 N3 P* i4 M; I& i- I( ^console.log(`from = ${from}`)      " w% f  o, u2 n4 \- r
console.log(`to = ${to}`)      
& p! V3 F) h8 r- R9 j8 c. }console.log(`value = ${value}`)      ( l+ H7 c1 Y$ J/ d3 U
console.log(`----BlockNumber (${blockNumber})----`)  });  * t! Z" @# {, O8 Y) z, A' s
最重要的区别是第9-12行,我们手动从组件中抓取正确的网络。 我们没有很好的truffle.deployed功能来实现这一步。 现在我们在truffle示例中执行与之前相同的操作,并通过调用contract.NAME_OF_EVENT来创建事件。 在这个版本中我没有放一个块号,但是你可以传递与truffle版相同的东西。
" p' O% Y1 F! U4 Y. Q" NRaw Web3 1.0.0 beta& T8 O; z6 s2 e, j
Web3确实为API带来了大量更改。 一个重大变化是我们必须使用webSockProvider来注册事件而不是httpProvider。
# e; T# B3 [2 D) [/ a8 _6 Oconst Web3 = require('web3') // Works with web3 1.0.0-beta27: J* c4 B' D* _( j' O
const contractArtifact = require('./build/contracts/TutorialToken.json')
3 S& }5 E1 L+ a. qconst web3 = new Web3()
- R2 \7 T) G# Y2 Z# L% Bconst 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.0! r( o0 Q" P% M% [: o1 Z! Q) `# f) k
const provider = new Web3.providers.WebsocketProvider(providerUrl)8 Y; u" J/ O# a0 W4 n& G: t2 s
web3.setProvider(provider)  @4 b1 e7 `5 a" N9 t7 i9 U( A& o
web3.eth.net.getId()  .then(networkId => {   
: j2 y" k2 w) ] const contractAddr = contractArtifact.networks[networkId].address   
+ Y% E8 d3 ]& t+ w% X' N8 iconst TutorialToken = new web3.eth.Contract(contractArtifact.abi, contractAddr)   
: b# i1 A! W; Z! j9 w0 eTutorialToken.events.Transfer({fromBlock: 0},
2 D' L# B: a# `+ Y6 R  ] function(error, event){ console.log(error) })      ' T/ p/ g2 X+ Y# y5 A. B
.on('data', (log) => {         p" ~0 }- g( I5 c
let { 4 X, ?" |* Q! |
returnValues: { from, to, value }, blockNumber } = log    . k) `0 R; m( ^5 _! {
    console.log(`----BlockNumber (${blockNumber})----`)        : P( o2 m; m0 |0 Q
console.log(`from = ${from}`)      
' G' c- ]' v6 L6 T/ Y# S/ v; y) a  console.log(`to = ${to}`)      
; I/ S0 [: u: }  ]8 z console.log(`value = ${value}`)        
7 l5 R! b& V! [2 R; {0 N1 W, _+ cconsole.log(`----BlockNumber (${blockNumber})----`)     2 l4 @  y3 `- U2 o: R
})      
( E% }$ |4 j+ X! o9 K4 h.on('changed', (log) => {     6 k& j( U1 B  K( c, K: c# y
   console.log(`Changed: ${log}`)   
- J6 M" R  [# }' y  })      .on('error', (log) => {   
8 W# t: y7 C& g     console.log(`error:  ${log}`)    3 S; x/ E) ~( P# M0 v
  })  })  ) q5 m) s/ ~* @9 x
此外,获取networkId也已更新。 但过程是一样的。 我们使用web3.eth.net.getId()获取networkId,然后从Artifact中选择正确的合同地址。 初始化合同现在是一个类构造函数,在web3.eth.Contract中有一个大写C. 最后,我们创建了事件监听器。 我们现在必须自己处理“数据”,“更改”和“错误”事件。 之前它包含在前面2个示例中的watch功能中。
' V( o1 R6 L# f. q) [% K0 I总结3 H" {$ O$ G& E
您应该了解如何将您的offchain服务连接到onchain事件。 这意味着您现在可以将区块链集成到现有基础架构中。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

李悔之2015 初中生
  • 粉丝

    1

  • 关注

    0

  • 主题

    13