github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/protocols/accounting.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:41</date> 10 //</624450105759502336> 11 12 13 package protocols 14 15 import ( 16 "time" 17 18 "github.com/ethereum/go-ethereum/metrics" 19 ) 20 21 //定义一些指标 22 var ( 23 //所有指标都是累积的 24 25 //单位贷记总额 26 mBalanceCredit metrics.Counter 27 //借记单位总额 28 mBalanceDebit metrics.Counter 29 //贷记字节总数 30 mBytesCredit metrics.Counter 31 //借记字节总数 32 mBytesDebit metrics.Counter 33 //贷记邮件总数 34 mMsgCredit metrics.Counter 35 //借记邮件总数 36 mMsgDebit metrics.Counter 37 //本地节点必须删除远程对等节点的次数 38 mPeerDrops metrics.Counter 39 //本地节点透支和丢弃的次数 40 mSelfDrops metrics.Counter 41 42 MetricsRegistry metrics.Registry 43 ) 44 45 //价格定义如何将价格传递给会计实例 46 type Prices interface { 47 //返回消息的价格 48 Price(interface{}) *Price 49 } 50 51 type Payer bool 52 53 const ( 54 Sender = Payer(true) 55 Receiver = Payer(false) 56 ) 57 58 //价格表示消息的成本 59 type Price struct { 60 Value uint64 61 PerByte bool //如果价格为每字节或单位,则为真 62 Payer Payer 63 } 64 65 //因为给了信息的价格 66 //协议以绝对值提供消息价格 67 //然后,此方法返回正确的有符号金额, 68 //根据“付款人”论点确定的付款人: 69 //“send”将传递“sender”付款人,“receive”将传递“receiver”参数。 70 //因此:如果发送人和发送人支付,金额为正,否则为负。 71 //如果收货方付款,金额为正,否则为负。 72 func (p *Price) For(payer Payer, size uint32) int64 { 73 price := p.Value 74 if p.PerByte { 75 price *= uint64(size) 76 } 77 if p.Payer == payer { 78 return 0 - int64(price) 79 } 80 return int64(price) 81 } 82 83 //余额是实际的会计实例 84 //余额定义了会计所需的操作 85 //实现在内部维护每个对等点的平衡 86 type Balance interface { 87 //使用远程节点“peer”将金额添加到本地余额中; 88 //正数=贷方本地节点 89 //负金额=借方本地节点 90 Add(amount int64, peer *Peer) error 91 } 92 93 //会计实现钩子接口 94 //它通过余额接口与余额接口连接, 95 //通过价格接口与协议及其价格进行接口时 96 type Accounting struct { 97 Balance //会计逻辑接口 98 Prices //价格逻辑接口 99 } 100 101 func NewAccounting(balance Balance, po Prices) *Accounting { 102 ah := &Accounting{ 103 Prices: po, 104 Balance: balance, 105 } 106 return ah 107 } 108 109 //SetupAccountingMetrics为P2P会计指标创建单独的注册表; 110 //这个注册表应该独立于任何其他指标,因为它在不同的端点上持续存在。 111 //它还实例化给定的度量并启动持续执行例程,该例程 112 //在经过的时间间隔内,将度量值写入级别数据库 113 func SetupAccountingMetrics(reportInterval time.Duration, path string) *AccountingMetrics { 114 //创建空注册表 115 MetricsRegistry = metrics.NewRegistry() 116 //实例化度量 117 mBalanceCredit = metrics.NewRegisteredCounterForced("account.balance.credit", MetricsRegistry) 118 mBalanceDebit = metrics.NewRegisteredCounterForced("account.balance.debit", MetricsRegistry) 119 mBytesCredit = metrics.NewRegisteredCounterForced("account.bytes.credit", MetricsRegistry) 120 mBytesDebit = metrics.NewRegisteredCounterForced("account.bytes.debit", MetricsRegistry) 121 mMsgCredit = metrics.NewRegisteredCounterForced("account.msg.credit", MetricsRegistry) 122 mMsgDebit = metrics.NewRegisteredCounterForced("account.msg.debit", MetricsRegistry) 123 mPeerDrops = metrics.NewRegisteredCounterForced("account.peerdrops", MetricsRegistry) 124 mSelfDrops = metrics.NewRegisteredCounterForced("account.selfdrops", MetricsRegistry) 125 //创建数据库并开始持久化 126 return NewAccountingMetrics(MetricsRegistry, reportInterval, path) 127 } 128 129 //发送需要一个对等点、一个大小和一个消息以及 130 //-使用价格接口计算本地节点向对等端发送大小消息的成本 131 //-使用余额界面的贷记/借记本地节点 132 func (ah *Accounting) Send(peer *Peer, size uint32, msg interface{}) error { 133 //获取消息的价格(通过协议规范) 134 price := ah.Price(msg) 135 //此邮件不需要记帐 136 if price == nil { 137 return nil 138 } 139 //评估发送消息的价格 140 costToLocalNode := price.For(Sender, size) 141 //做会计工作 142 err := ah.Add(costToLocalNode, peer) 143 //记录度量:只增加面向用户的度量的计数器 144 ah.doMetrics(costToLocalNode, size, err) 145 return err 146 } 147 148 //接收需要一个对等点、一个大小和一个消息以及 149 //-使用价格接口计算从对等端接收大小消息的本地节点的成本 150 //-使用余额界面的贷记/借记本地节点 151 func (ah *Accounting) Receive(peer *Peer, size uint32, msg interface{}) error { 152 //获取消息的价格(通过协议规范) 153 price := ah.Price(msg) 154 //此邮件不需要记帐 155 if price == nil { 156 return nil 157 } 158 //评估接收消息的价格 159 costToLocalNode := price.For(Receiver, size) 160 //做会计工作 161 err := ah.Add(costToLocalNode, peer) 162 //记录度量:只增加面向用户的度量的计数器 163 ah.doMetrics(costToLocalNode, size, err) 164 return err 165 } 166 167 //记录一些指标 168 //这不是错误处理。'err'由'send'和'receive'返回 169 //如果违反了限制(透支),则“err”将不为零,在这种情况下,对等方已被取消。 170 //如果违反了限制,“err”不等于零: 171 //*如果价格为正数,则本地节点已记入贷方;因此“err”隐式地表示远程节点已被删除。 172 //*如果价格为负,则本地节点已被借记,因此“err”隐式地表示本地节点“透支” 173 func (ah *Accounting) doMetrics(price int64, size uint32, err error) { 174 if price > 0 { 175 mBalanceCredit.Inc(price) 176 mBytesCredit.Inc(int64(size)) 177 mMsgCredit.Inc(1) 178 if err != nil { 179 //增加由于“透支”而丢弃远程节点的次数 180 mPeerDrops.Inc(1) 181 } 182 } else { 183 mBalanceDebit.Inc(price) 184 mBytesDebit.Inc(int64(size)) 185 mMsgDebit.Inc(1) 186 if err != nil { 187 //增加本地节点对其他节点进行“透支”的次数 188 mSelfDrops.Inc(1) 189 } 190 } 191 } 192