Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

优化向钱包导入地址的性能 #635

Open
sunhantao opened this issue Sep 16, 2020 · 2 comments
Open

优化向钱包导入地址的性能 #635

sunhantao opened this issue Sep 16, 2020 · 2 comments
Labels
Performance improve performance

Comments

@sunhantao
Copy link
Collaborator

sunhantao commented Sep 16, 2020

当前的实现

  • 向钱包导入地址后,对于每个分支,从创世块开始向下遍历长链。
  • 将每个块从block.dat读取出来,再序列化
  • 从交易集合中选择与导入地址相关的放入到wallet中

优点

  • 当地址相关的交易非常多时,效率高
  • 使用resyncwallet时,如果wallet中地址较多、关联的交易较多,效率高

缺点

  • 当地址相关的交易较少时,效率很低
  • 实际情况下,单个地址导入的平均效率低

改进方案

  • 扩展block.dat的结构在CBlockEx基础上增加一个相关地址前序交易位置的数组
  • block.dat中每个交易对应数组中的一项,每项数据包含两个二元组,第一个二元组是from地址的,第二个二元组是to地址的。每个二元组有两个数据(PrevDiskPos, txDiskPos),PrevDiskPos表示该地址上一个交易索引的位置,txDiskPos表示当前交易内容的位置
  • 对于每一条分支创建一个leveldb数据库AddrTxIndex,key是上链的地址,value是最后一个交易索引的位置
  • 当长链发生变化时,需要回滚更新AddrTxIndex(类似unspent表)
  • 兼容性:
    • 需要根据原block.dat重构所有文件和数据库
    • 重构依据是block.dat中是否使用了新的nMagicNum,重构入口在checkrepair之前
    • 首选清除原数据库(除block.dat,votedata.dat)
    • 依次读取block.dat的块,不验证交易、块,写入到newblock.dat中
    • 全部更新后,将newblock.dat改名为block.dat

查询某个地址的所有交易

  • 查询每个fork的AddrTxIndex,如果没有则没有交易,如果有记录获得最后一个交易索引位置IndexPos
  • 读取文件索引位置的二元组(PrevDiskPos, txDiskPos),获得了最后一个交易的位置txDiskPos保存下来,和上一个交易索引的位置
  • 依次类推,直到PrevDiskPos = 0表明再无交易
  • 将交易的位置信息由早到晚将交易从block.dat中取出,交由wallet。

优点

  • 扩展性强
  • 精准度高,检索的仅仅是该地址的交易所有交易
  • 对于交易不多的地址效率高

缺点

  • 交易量大的地址效率低于原实现

两种方案同时存在

  • 在RPC importprivkey, importpubkey, importkey, importtemplate中增加参数synctype,在参数sync开启时,默认使用新方式,也可以设置为旧方式(交易量大的地址)
  • 优化RPC importwallet,在地址全部导入后调用resyncwallet(旧方式)
  • 再RPC resyncwallet 中增加参数synctype,默认使用旧方式,也可以设置为新方式
@sunhantao sunhantao added the Performance improve performance label Sep 16, 2020
@sunhantao
Copy link
Collaborator Author

sunhantao commented Sep 16, 2020

过滤器的方案

  • 在CBlockIndex中增加一个过滤器字段,将该块中所有交易涉及的地址集合放到过滤器上。根据交易的大小该字段的大小范围约为0 - 5k
  • 在检索时遍历CBlockIndex并判断地址是否有可能在这个块中,如在将块读出来筛选交易

优点

  • 效率比原方案快的多
  • 代码容易编写,改动量小
  • 处理简单,不用考虑回滚

缺点

  • 占用内存大,需要考虑blockindex无法在内存全放下的情况(原代码随着时间推移也有blockindex不能全放内存的时候,只是该方案加快了这个临界点的到来)
  • 有误报率,且过滤器的容量和误报率成反比,这个误报率的数值需要考虑
  • blockindexdb数据库数据比较大可能有读取速度问题

@sunhantao
Copy link
Collaborator Author

全局过滤器方案

  • 对于每一个fork有一个全局过滤器
  • 过滤器hash的内容是addr + blockhash
  • 通过内存中计算该地址是否可能在某个block中有交易,读取block数据,筛选其中的交易

优点

  • 效率高
  • 支持多地址索引

缺点

  • 占用内存大,未来可能考虑将过滤器部分放在文件中
  • 有误报率

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Performance improve performance
Projects
None yet
Development

No branches or pull requests

1 participant