tendermint提供的RPC接口(三)

tendermint RPC

接上两篇:

tendermint提供的RPC接口(一)

tendermint提供的RPC接口(二)


本文是系列文章第三篇,主要介绍如何自定义订阅事件。

/subscribe

说明:通过wensocket订阅事件。

想要订阅某个事件,需要提供一个字符串表达式,格式是“condition AND condition ”(只能用AND不能用OR)condition的格式是“key operation operand”

key是一个字符串(\t\n\r()'"=><不允许出现在key)

operation可以是“=”“<”“<=”“>”“> =” "CONTAINS"

operand可以是一个字符串(要用单引号转义),数字,日期或者事件。

比如:

tm.event = 'NewBlock' // 新区快产生
tm.event = 'CompleteProposal' // 完成一个提案
tm.event = 'Tx' AND tx.hash = 'XYZ' // 某一笔交易
tm.event = 'Tx' AND tx.height = 5 // 第五个块的所有交易
tx.height = 5 // 第五个块的所有交易

tendermint提供了几个预定义的key:tm.event,tx.hash,tx.height。但是用户可以通过重定义DeliverTx的响应来增加key,用以订阅其他的事件。例如定义以下event

types.ResponseDeliverTx{
   Events: []types.Event{
      {
         Type: "rewards.withdraw",
         Attributes:
         common.KVPairs{
            common.KVPair{Key: []byte("address"), Value: []byte("AddrA")},
            common.KVPair{Key: []byte("source"), Value: []byte("SrcX")},
            common.KVPair{Key: []byte("amount"), Value: []byte("...")},
            common.KVPair{Key: []byte("balance"), Value: []byte("...")},
         },
      },
      {
         Type: "rewards.withdraw",
         Attributes: common.KVPairs{
            common.KVPair{Key: []byte("address"), Value: []byte("AddrB")},
            common.KVPair{Key: []byte("source"), Value: []byte("SrcY")},
            common.KVPair{Key: []byte("amount"), Value: []byte("...")},
            common.KVPair{Key: []byte("balance"), Value: []byte("...")},
         },
      },
      {
         Type: "transfer",
         Attributes: common.KVPairs{
            common.KVPair{Key: []byte("sender"), Value: []byte("AddrC")},
            common.KVPair{Key: []byte("recipient"), Value: []byte("AddrD")},
            common.KVPair{Key: []byte("amount"), Value: []byte("...")},
         },
      },
   },
}

所有事件都由eventTypeeventAttrKey形式的符合键索引,在上面的示例中,将对以下键进行索引:

  • rewards.withdraw.address
  • rewards.withdraw.source
  • rewards.withdraw.amount
  • rewards.withdraw.balance
  • transfer.sender
  • transfer.recipient
  • transfer.amount
  • 允许多个事件类型具有重复的键,并且可以用于对唯一和不同事件进行分类。
  • 在上面的示例中,在密钥rewards.withdraw.address下索引的所有事件将具有以下存储和可查询的值:AddrA,AddrB

  • 创建各种类型的交易订阅:
  • query.MustParse("tm.event = 'Tx' AND rewards.withdraw.address = 'AddrA'")
  • query.MustParse("tm.event = 'Tx' AND rewards.withdraw.address = 'AddrA' AND rewards.withdraw.source = 'Y'")
  • query.MustParse("tm.event = 'Tx' AND transfer.sender = 'AddrA'")

  • 这几种是无返回值的:
  • query.MustParse("tm.event = 'Tx' AND transfer.sender = 'AddrZ'")
  • query.MustParse("tm.event = 'Tx' AND rewards.withdraw.address = 'AddrZ'")
  • query.MustParse("tm.event = 'Tx' AND rewards.withdraw.source = 'W'")

  • 下面是示例。
  • 自定义的event代码:
  • var events []types.Event
    if strings.HasPrefix(k,"a"){
    events = []types.Event{
    {
    Type: "string",
    Attributes: []common.KVPair{
    {Key: []byte("startWith"), Value: []byte("a")},
    {Key: []byte("key"), Value: key},
    },
    },
    }
    }
    if strings.HasPrefix(k,"b"){
    events = []types.Event{
    {
    Type: "string",
    Attributes: []common.KVPair{
    {Key: []byte("startWith"), Value: []byte("b")},
    {Key: []byte("key"), Value: key},
    },
    },
    }
    }
  • 订阅代码分为2个线程:
  • func main() {
    cli := client.NewHTTP("http://localhost:26657", "/websocket")
    err := cli.Start()
    if err != nil {
    fmt.Println(err)
    return
    }
    defer cli.Stop()
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()
    //query := "app.key='author'"
    txs, err := cli.Subscribe(ctx, "test-client", "string.startWith = 'a'")
    if err != nil {
    fmt.Println("错误信息", err)
    return
    }
    for tx := range txs {
    fmt.Println("startWithA接收到消息:\n", tx)
    }
    }
  • func main() {
    cli := client.NewHTTP("http://localhost:26657", "/websocket")
    err := cli.Start()
    if err != nil {
    fmt.Println(err)
    return
    }
    defer cli.Stop()
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()
    //query := "app.key='author'"
    txs, err := cli.Subscribe(ctx, "test-client", "string.startWith = 'b'")
    if err != nil {
    fmt.Println("错误信息", err)
    return
    }
    for tx := range txs {
    fmt.Println("startWithB接收到消息:\n", tx)
    }
    }

    分别发送交易:

    curl -s localhost:26657/broadcast_tx_commit?tx=\"aunt=a1234\"

    curl -s localhost:26657/broadcast_tx_commit?tx=\"buss=b5678\"

    可以看到两个窗口分别收到消息:

    attachments-2019-09-h1FsjKsq5d7778ae76464.png

    attachments-2019-09-OApWhrVI5d7778be87acc.png


    这只是一个示例,在实际使用过程中会更加复杂一些,例如对某个交易地址的监控,对大额转账的监控等等。

  • 发表于 2019-09-10 18:22
  • 阅读 ( 75 )
  • 分类:Tendermint

0 条评论

请先 登录 后评论
不写代码的码农
曹欢

区块链开发

1 篇文章

作家榜 »

  1. 社区运营-小以 623 文章
  2. 社区运营-小链 243 文章
  3. 涂晶 82 文章
  4. 于中阳Mercina-zy 79 文章
  5. 李晓琼 44 文章
  6. 兄弟连区块链培训 42 文章
  7. 吴寿鹤 38 文章
  8. John-smith 25 文章