Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
您的应用程序不可避免地需要与“现实世界”API进行对话,例如是发送电子邮件,查询更多数据,或充当发起其他处理的信号。 下面让我们探讨如何让以太坊智能合约与脱链服务互通。' i8 Z7 C; _- y
简而言之,您可以在处理事务时使智能合约发出事件。一旦事务被挖掘,事件数据就可以读取。在下图中,您可以看到您的DApp发出的事件可以从您的API的任何服务中检索。
) D; A( z3 l; U( Q) Q5 K& S5 a5 M  v/ Z' g. j0 P4 i: F
目前有两种方法可以获取事件数据:
) P7 ^8 f5 K9 w+ f5 c4 ?) c" w目前有两种方法可以获取事件数据:
) ]1 M* N4 C2 [! X! E7 p选项1:使用getTransactionReceipt8 n0 U* @' i+ \3 z* I9 h8 J; U( D
选项2:为事件注册监听器$ r  B, v* Z4 W" ]. a
您可以使用选项1来获取事件数据,但是可能会存在潜在问题,因为在区块被挖掘之前收据是空的。你可以提出调查,但这很难做到。; e" e+ o( e% E! U) n) c- _# Q  K
另外,根据网络流量和gasPrice设置,交易可能长时间不会被打包。请注意,事件只有在被挖掘成区块后才会被传播。这意味着可以为任何一个区块调用多个事件。& r3 D# I% C0 \( W8 Z$ J; ~* O
solidity事件+ S  E, p4 B: z7 t9 M
在solidity里创建事件需要两个步骤:定义事件,发出事件。
3 X( O) l2 W0 h0 G; W- H    pragma solidity ^0.4.18;
* A+ c6 m" d; l: o4 G; X! l0 t2 Ccontract MyContract {  6 I5 J7 \; M. T: N* X$ v
event Transfer(address indexed from, address indexed to, uint256 value); /* This is an event */  6 a! d! S" o. n, e
function MyContract() {} /* a constructor */  5 W" q- H$ Z4 P6 P; p! h8 O+ x+ ~
function transfer(address _to) public {   : d6 y3 D6 |: @5 ?! }$ E9 P( y
Transfer(msg.sender, _to, msg.value);  }}  
6 f1 I0 X9 l  h( O! q注意事件Transfer是如何在第5行创建的,然后在函数传输中使用它发出Transfer事件(第10行)。 但会告诉你如何使用一个事件,如果我们用0x123调用传递函数,并从0x4444的地址发送1以太,则事件触发传输事件并应返回[0x4444,0x123,BigNumber(1以太)]。
+ E' t9 L3 j+ N1 w5 P) ^监听事件% ]  t6 ~2 Q* ?5 v
以太坊实现了他们的JSON RPC规范,但任何人都可以用他们选择的语言实现自己的库。 我们将使用Truffle和原始web3 Javascript API。 监听事件的一般流程如下:, U/ I2 E0 F: F& G) I8 P
1、加载合同组件) m, u- F7 M0 b5 i3 Z- y% T0 Z5 W
2、配置web3和使用truffle提供程序
  H1 E2 K+ ~1 [/ e5 ~, M1 B4 j3、识别网络id% @0 u0 C! q2 L/ @2 R2 t
4、从合同组件中获取正确的合同地址3 }" `) I- Y: k, A# P, f7 R! N
5、获取JavaScript合约实例0 O$ ]! F, k1 q1 ~% T1 c
6、使用可选配置调用contractInstace.NAME_OF_EVENT
" k! O$ P* A: U$ J2 }9 G: ?下面我们有3个样本使用Truffle,Web3在1.0 beta之前,Web3在1.0 beta之后。3 x, p8 o4 E/ m2 t1 ~
Truffle API
2 l9 A1 T  b% {" qTruffle是web3的一个很好的包装器,它提供了一些便利功能,使用更加轻松。 看一下下面的代码示例:
: T0 `# k5 z6 w' ~- y; V2 w* p6 m8 fconst Web3 = require('web3') // Web3 0.20.4 or web3 1 beta2 P: Y" X; G" _7 U2 F4 _
const truffleContract = require("truffle-contract")+ C$ d5 j# K5 A) J- g8 z' B0 J
const contractArtifact = require('./build/contracts/TutorialToken.json')
: _: ^6 V) B3 F2 }! xconst providerUrl = 'http://localhost:8545'! @7 q* i$ R+ [; C; v& W( j
const provider = new Web3.providers.HttpProvider(providerUrl), T) Q2 L- j0 G8 K6 i6 N5 W) E' c) x
const contract = truffleContract(contractArtifact)/ b( K# f$ n& X4 [. K( C$ P
contract.setProvider(provider)
/ t* \: S3 e3 e/ @8 H// dirty hack for web3@1.0.0 support for localhost testrpc, see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment331084530
$ L8 j) c, _3 }" `if (typeof contract.currentProvider.sendAsync !== "function") {
% h* k& }, Y: [) l: d+ b) S contract.currentProvider.sendAsync = function() {      
$ w5 ]  t2 q4 C3 ~return contract.currentProvider.send.apply(      
  @) w' Q$ k% @/ \: k3 { contract.currentProvider,           
+ y1 ^6 t( ?0 W! q8 }7 z( c$ n arguments     
- s  x4 W. ~8 O5 G' v );   
# M/ y' C4 V" W2 t2 k3 A7 P};  }
2 X$ }% y" \% j1 m  ]6 p+ Y5 |contract.deployed()  .then(contractInstance => {   
: w/ i: n) K0 y# m1 B8 |! ?& | const event = contractInstance.Transfer(null, {fromBlock: 0}, (err, res) => {    - L' P  M$ F! [! J( v
  if(err) {      $ ^  U$ h, g0 X: {
  throw Error(err)     * U' W) E' B4 v; h
}    })   
- D' Y/ g6 p' \$ k" `  G, Y event.watch(function(error, result){      
  Q+ L6 ]* X( t; g' v6 _if (error) { return console.log(error) }     / ^, U! l6 i5 F9 V+ G  o
if (!error) {      
% z  C2 N9 C0 y0 p // DO ALL YOUR WORK HERE!      
$ e0 q: W: @: l* t let { args: { from, to, value }, blockNumber } = result      
6 \7 {8 j$ r7 v6 t+ u: { console.log(`----BlockNumber (${blockNumber})----`)        " N+ Q6 j. c8 {/ C; W9 S/ G
console.log(`from = ${from}`)      
! S. K3 _/ x( C; L& f console.log(`to = ${to}`)      
0 D. @9 ?! m, A. s! F4 a console.log(`value = ${value}`)       ' n  y! U4 |. S( s) U. x8 C
console.log(`----BlockNumber (${blockNumber})----`)   
3 S4 G; \# M  A/ ?  t   }   8 h) D8 V; S  j. D  a! y
})  }) & M9 c5 I; z: [) Y! o. c; r0 ^
.catch(e => {   : E( d8 e. i1 P) _" G9 R
console.error('Catastrophic Error!')  + _# E. L. ~/ ~4 a, I
  console.error(e) % `2 e" [- B( Y9 c1 F* k
})  
$ s1 z8 u3 F9 F前9行需要一些模块,并设置truffle和web3能够正常网络通信。 第12-19行作为hack使其与web3一起使用,可以忽略。 工作从第21行开始,带有contract.deployed()。 这是一个很好的truffle辅助函数,可以从创建并保存到./build/contracts的工件中选择正确的合同地址。 返回contractInstance(第23行)后,我们通过调用contractInstance.NAME_OF_EVENT来“创建”该事件。 存在更多选项,可在此处找到。 我从0块中选择,因为它是我们自己的testrpc。 对于您的合同,最好选择更接近合同创建时的块编号。) x, b' v2 C. p+ {. Z1 \* d3 P
Raw Web3(0.20.4及以下)' y& t$ s* p$ \$ b
对于第二个示例,我们将直接使用Web3。 除了上一个示例中的hack之外,代码流程类似。
: H9 ^6 b8 O  \; o) c  const Web3 = require('web3') // Works with web3 0.20.4
- [5 H: n  G5 @4 I' nconst contractArtifact = require('./build/contracts/TutorialToken.json')
) ?: A, T7 x- u+ U9 x2 tconst web3 = new Web3()
4 L$ L. m/ ^% e, i8 H& j. u3 P' I$ fconst providerUrl = 'http://localhost:8545'
  x/ _& \6 ~+ |+ f; v/ U& l, }# Xconst provider = new Web3.providers.HttpProvider(providerUrl)web3.setProvider(provider)
+ |: Z' _: e0 C6 w; q; Wconst networkId = web3.version.networkconst
* M4 X' E( Z5 i: |2 WcontractAddr = contractArtifact.networks[networkId].address
7 _! k6 u1 C# l" B$ \- cconst TutorialToken = web3.eth.contract(contractArtifact.abi, contractAddr)
5 Y7 [3 e: H1 V: qconst contract = TutorialToken.at(contractAddr)2 a6 Z/ l% U: \. G
const event = contract.Transfer()' h5 [/ `( p9 m
event.watch(function(error, result){     \; V( g. ~- z7 L
if (error) { return console.error(error) }   
2 t( F& l) g# Z* T/ ]0 w4 z  let { args: { from, to, value }, blockNumber } = result      , _- N* E7 ?$ s; k9 T/ P
console.log(`----BlockNumber (${blockNumber})----`)      
2 Z  j! f% Z( J8 E1 _( _console.log(`from = ${from}`)      * I7 ?* i" C) d: [$ u
console.log(`to = ${to}`)      5 {) _- v, N! X* I
console.log(`value = ${value}`)      
) x" t4 g$ n9 u' ~* F- V2 _console.log(`----BlockNumber (${blockNumber})----`)  });  - h9 C& @  Y0 N* w9 n  [9 Y
最重要的区别是第9-12行,我们手动从组件中抓取正确的网络。 我们没有很好的truffle.deployed功能来实现这一步。 现在我们在truffle示例中执行与之前相同的操作,并通过调用contract.NAME_OF_EVENT来创建事件。 在这个版本中我没有放一个块号,但是你可以传递与truffle版相同的东西。1 Y: y( K" U1 V7 l
Raw Web3 1.0.0 beta1 \, A, p$ }# G% b- `% J
Web3确实为API带来了大量更改。 一个重大变化是我们必须使用webSockProvider来注册事件而不是httpProvider。: w2 g; U+ g& m* M+ l! i, f3 I" l+ m9 p
const Web3 = require('web3') // Works with web3 1.0.0-beta277 x* ~1 v0 @2 m- ]( Y
const contractArtifact = require('./build/contracts/TutorialToken.json')
5 E9 @; A+ w4 Cconst web3 = new Web3()
- k! Z' \* d4 b% O. h$ @: Pconst 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
2 g1 B( e' _8 r# t$ `+ U& sconst provider = new Web3.providers.WebsocketProvider(providerUrl)
' E* L+ O; i' ?: Y) |8 Sweb3.setProvider(provider)
% L# A2 ~( p* T! z+ w/ X6 K% Zweb3.eth.net.getId()  .then(networkId => {   * D, d  r- `2 R% d# }  R0 o) n$ `
const contractAddr = contractArtifact.networks[networkId].address   
" Y8 R* L) q* j: L) oconst TutorialToken = new web3.eth.Contract(contractArtifact.abi, contractAddr)    3 }8 T) s6 e; }9 r
TutorialToken.events.Transfer({fromBlock: 0},
# T* ~- U) {! a0 ` function(error, event){ console.log(error) })      " U3 N1 J  }- @+ o
.on('data', (log) => {       6 J8 E1 U, @* X
let { ( s3 l' V  J4 ^6 z8 u
returnValues: { from, to, value }, blockNumber } = log    9 ^6 j9 @. @$ s% N
    console.log(`----BlockNumber (${blockNumber})----`)        
% w" w# @1 P! {, V, sconsole.log(`from = ${from}`)      
  t7 q& C7 g  i  o  console.log(`to = ${to}`)       - o3 u4 N; {! h* s
console.log(`value = ${value}`)        $ W0 M7 f* i4 ]7 A; I# \
console.log(`----BlockNumber (${blockNumber})----`)     # [) L& B& j, L
})      4 m8 e" q. a- b1 o5 q3 K( u
.on('changed', (log) => {     
. I: ~7 h5 F! o: T! P8 ^   console.log(`Changed: ${log}`)   
9 F$ Z9 S: R+ V  })      .on('error', (log) => {   6 t$ |, y2 E1 r& J5 X, ~
     console.log(`error:  ${log}`)    + z4 O6 }& q0 C+ ?' O  O/ a7 ?2 s
  })  })  4 o% t4 X' c8 R% E
此外,获取networkId也已更新。 但过程是一样的。 我们使用web3.eth.net.getId()获取networkId,然后从Artifact中选择正确的合同地址。 初始化合同现在是一个类构造函数,在web3.eth.Contract中有一个大写C. 最后,我们创建了事件监听器。 我们现在必须自己处理“数据”,“更改”和“错误”事件。 之前它包含在前面2个示例中的watch功能中。
9 X6 M: c! k  ^' Z! z$ M& n总结
. E4 u1 J: M) k* D8 Q9 `& C' K+ ~您应该了解如何将您的offchain服务连接到onchain事件。 这意味着您现在可以将区块链集成到现有基础架构中。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

李悔之2015 初中生
  • 粉丝

    1

  • 关注

    0

  • 主题

    13