1.waiter_addr_info.py:
处理new tx块数据,解析增量,统计出来addr_info表:
multi_address 用于记录多签编码地址到原地址的映射,统计出multi_address表
import hashlib
import binascii
# 多签地址合并加密
def btc_multsig_encrypt(addresses):
addr_str='_'.join(addresses)
return hashlib.md5(addr_str.encode('utf-8')).hexdigest()
# 循环冗余校验
def crc32_address(address, cnt):
"""
将地址转成crc32的值,并按照cnt取余,用于将redis的key均匀分配到各个桶
:param address: 地址
:param cnt: 桶的总数
:return: 桶的名字
"""
return binascii.crc32(address.encode('utf-8')) % cnt
- key 为 CRC32校验返回的一个均匀分布的 32位的整数,
- 每个桶中存储200左右的数量不影响数据库查询性能, 总条数为1000万,每个桶设计容量为200,那么可以算出桶的数量.
-
注意:每个桶存入的数量不能超过512条,当单个桶的地址数超出阈值时甚至会出发ziplist向hashtable转变,导致内存使用率的快速上升
redis 分桶存储
2. * hanler_new_tx 最后存入kafka topic的数据格式如下:


-
hanler_new_tx 最后存入redis库中的格式如下:
hanler_new_tx 最后存入redis库中的格式

key为: chain_monitor_cache_hanler
3.字段confirmations的含义以及作用:
'confirmations' 这个字段是验证数的意思,是int类型的一个字段在cache中判断,也就是这个数字如果小于6那么就需要缓存,大于6就认为这个块已经验证了,以后不会再改变
-
这个字段是原始块数据中的
这个跟时间有关,刚出的块的这个子弹是小于6的!
比如当前是630000块,那么629999块的验证数就是1,629998就是2,依次类推
那这些块的验证数还会跟着时间改变啊
比如现在出到630010块了,那之前的629998的验证数就由2变成了12了啊,这个验证数只在cache那个地方用到了
那不是只要出来一个块,所有的块的验证数都要发生一次改变啊
链上它自己会改变confirmations
有兴趣可以看下源码,我觉得它肯定不是每次改全量数据库,而是按照请求时刻对应去取的
4.waiter_addr_info 里面的数据结构:
block_data 和 txs,tx就是一个交易, vi 就是一个vin

5.UTXO:未使用的交易输出,比特币核心概念之一
http://c.biancheng.net/view/1895.html
6.python语法糖之:
- 序列解包
https://blog.csdn.net/yilovexing/article/details/80576788 - 序列赋值
https://blog.csdn.net/weixin_30865427/article/details/99923461?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-4
7.multi_address 多签地址库(存入的mongoDB)的数据格式
multi_address 多签地址库

_id : MD5 加密之后的str
8. Python中“+”与“join”的区别
合并字符串与拼接字符串不同,它会将多个字符串采用固定的分隔符连接在一起。合并字符串可以使用字符串对象的join()方法实现,语法结构如下:
strnew = string.join(iterable)

strnew:表示合并后生成的新字符串
string:字符串类型,用于指定合并时的分隔符
iterable:可迭代对象,该迭代对象中的所有元素(字符串表示)将被合并为一个新的字符串。string作为边界点分割出来
list_name = ['绮梦', '冷伊一', '香凝', '黛兰']
print('*'.join(list_name))
输出:绮梦*冷伊一*香凝*黛兰
注意:
如果要合并str1和str2,可以用str1+str2,但是不能用str1.join(str2),这个是错误的。
应该避免在循环中使用“+”和“+=”运算符累加字符串。这是因为字符串是不可变的,这样做会创建不必要的临时对象。推荐将每个子字符串加入列表,然后在循环结束后使用join()方法连接列表。
因为字符串是不可变类型,如果要进行字符串的拼接,只能申请新的内存保存新拼接的字符串。这样每进行一次拼接就需要申请一次内存并存储结果,这会使得程序效率低。
join只会进行一次内存申请,因此运行效率相对于+会快很多。
9. address_info 库的解读:
-
一个地址可能出现在vin和vout:
-
waiter_address_info.py的原理:
①循环遍历解读每个区块里面的地址的,分为vin部分和vout部分, vout是正值,vin是负值
②
一个地址的增量的原理
- 就是一个地址下的余额,收到的金额,支出的金额,交易总数,未被花费的输出数(utxo_count)
- 数据结构:
对于存入mongo库的增量信息就是,地址不断的出现在不同的块中的vin或vout,地址 如上面的"17A16QmavnUfCW11DAApiJxp7ARnxN5pGX
" 为_id 的vin和vout 的增量解析之后的,如果有这地址,就将增量消息更新写入mongo,如果没有此地址,就新写入
增量信息存入mongo
upds = [UpdateOne({'_id': addr}, {'$inc': inc}, upsert=True) for addr, inc in increment.items()]
await self.mongo_db.bulk({config.MONGO_COLLECTION: upds})
10.monngo 写入数据时不同参数(修改器)的方式解析
[mongo的基本操作参考点击这里!]
(https://www.cnblogs.com/aademeng/articles/9779271.html)
$ inc 操作符接收正的和负的值
如果指定的字段不存在则$inc操作符创建这个字段并且设置这个字段的值为指定的在值;
使用$inc操作符的字段的值如果值为null则将会报异常;
$inc操作符是原子性的在单个文档中
{'$ inc': inc} 和 {'$set': {'multi_address': addrs}}
我们再看一个例子:
condition = {'age': {'$gt': 20}}
result = collection.update_one(condition, {'$inc': {'age': 1}})
print(result)
print(result.matched_count, result.modified_count)
这里指定查询条件为年龄大于20,然后更新条件为{'$inc': {'age': 1}},
也就是年龄加1,执行之后会将第一条符合条件的数据年龄加
其返回结果是UpdateResult类型。然后分别调用matched_count和modified_count属性,可以获得匹配的数据条数和影响的数据条数
如果在update中不设置第三个参数为true,在查询不到要更新的文档时,不做任何操作;如果设置第三个参数为true,则会在没有找到文档的情况下新建一个文档。
1. upds = [UpdateOne({'_id': addr}, {'$inc': inc}, upsert=True) for addr, inc in increment.items()]
2. upds = [UpdateOne({'_id': ept_addr}, {'$set': {'multi_address': addrs}}, upsert=True)
11.在函数 def save_increment 中:
-
increment的数据结构:
-
upds 数据结构:
image.png
12.mongo2_database.py 中 bulk_write的参数bd数据结构:

13.one_addr_info 和 tx ,vi的数据结构:


14.多签地址的数据样式:

-
tx_count', 'input_tx_count', 'output_tx_count 的增量
-
'last_receive_block', 'first_receive_block', 'last_spend_block', 'first_spend_block' 暂时没有处理
这四个字段不能用,因为不能和其他增量一起处理。就没处理











