github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/blockproc/drivermodule/driver_txs.go (about) 1 package drivermodule 2 3 import ( 4 "io" 5 "math" 6 "math/big" 7 8 "github.com/unicornultrafoundation/go-helios/native/idx" 9 "github.com/unicornultrafoundation/go-u2u/common" 10 "github.com/unicornultrafoundation/go-u2u/core/state" 11 "github.com/unicornultrafoundation/go-u2u/core/types" 12 "github.com/unicornultrafoundation/go-u2u/log" 13 14 "github.com/unicornultrafoundation/go-u2u/gossip/blockproc" 15 "github.com/unicornultrafoundation/go-u2u/native" 16 "github.com/unicornultrafoundation/go-u2u/native/drivertype" 17 "github.com/unicornultrafoundation/go-u2u/native/iblockproc" 18 "github.com/unicornultrafoundation/go-u2u/native/validatorpk" 19 "github.com/unicornultrafoundation/go-u2u/u2u" 20 "github.com/unicornultrafoundation/go-u2u/u2u/contracts/driver" 21 "github.com/unicornultrafoundation/go-u2u/u2u/contracts/driver/drivercall" 22 "github.com/unicornultrafoundation/go-u2u/u2u/contracts/driver/driverpos" 23 ) 24 25 const ( 26 maxAdvanceEpochs = 1 << 16 27 ) 28 29 type DriverTxListenerModule struct{} 30 31 func NewDriverTxListenerModule() *DriverTxListenerModule { 32 return &DriverTxListenerModule{} 33 } 34 35 func (m *DriverTxListenerModule) Start(block iblockproc.BlockCtx, bs iblockproc.BlockState, es iblockproc.EpochState, statedb *state.StateDB) blockproc.TxListener { 36 return &DriverTxListener{ 37 block: block, 38 es: es, 39 bs: bs, 40 statedb: statedb, 41 } 42 } 43 44 type DriverTxListener struct { 45 block iblockproc.BlockCtx 46 es iblockproc.EpochState 47 bs iblockproc.BlockState 48 statedb *state.StateDB 49 } 50 51 type DriverTxTransactor struct{} 52 53 type DriverTxPreTransactor struct{} 54 55 func NewDriverTxTransactor() *DriverTxTransactor { 56 return &DriverTxTransactor{} 57 } 58 59 func NewDriverTxPreTransactor() *DriverTxPreTransactor { 60 return &DriverTxPreTransactor{} 61 } 62 63 func InternalTxBuilder(statedb *state.StateDB) func(calldata []byte, addr common.Address) *types.Transaction { 64 nonce := uint64(math.MaxUint64) 65 return func(calldata []byte, addr common.Address) *types.Transaction { 66 if nonce == math.MaxUint64 { 67 nonce = statedb.GetNonce(common.Address{}) 68 } 69 tx := types.NewTransaction(nonce, addr, common.Big0, 1e10, common.Big0, calldata) 70 nonce++ 71 return tx 72 } 73 } 74 75 func maxBlockIdx(a, b idx.Block) idx.Block { 76 if a > b { 77 return a 78 } 79 return b 80 } 81 82 func (p *DriverTxPreTransactor) PopInternalTxs(block iblockproc.BlockCtx, bs iblockproc.BlockState, es iblockproc.EpochState, sealing bool, statedb *state.StateDB) types.Transactions { 83 buildTx := InternalTxBuilder(statedb) 84 internalTxs := make(types.Transactions, 0, 8) 85 86 // write cheaters 87 for _, validatorID := range bs.EpochCheaters[bs.CheatersWritten:] { 88 calldata := drivercall.DeactivateValidator(validatorID, drivertype.DoublesignBit) 89 internalTxs = append(internalTxs, buildTx(calldata, driver.ContractAddress)) 90 } 91 92 // push data into Driver before epoch sealing 93 if sealing { 94 metrics := make([]drivercall.ValidatorEpochMetric, es.Validators.Len()) 95 for oldValIdx := idx.Validator(0); oldValIdx < es.Validators.Len(); oldValIdx++ { 96 info := bs.ValidatorStates[oldValIdx] 97 // forgive downtime if below BlockMissedSlack 98 missed := u2u.BlocksMissed{ 99 BlocksNum: maxBlockIdx(block.Idx, info.LastBlock) - info.LastBlock, 100 Period: native.MaxTimestamp(block.Time, info.LastOnlineTime) - info.LastOnlineTime, 101 } 102 uptime := info.Uptime 103 if missed.BlocksNum <= es.Rules.Economy.BlockMissedSlack { 104 missed = u2u.BlocksMissed{} 105 prevOnlineTime := native.MaxTimestamp(info.LastOnlineTime, es.EpochStart) 106 uptime += native.MaxTimestamp(block.Time, prevOnlineTime) - prevOnlineTime 107 } 108 metrics[oldValIdx] = drivercall.ValidatorEpochMetric{ 109 Missed: missed, 110 Uptime: uptime, 111 OriginatedTxFee: info.Originated, 112 } 113 } 114 calldata := drivercall.SealEpoch(metrics) 115 internalTxs = append(internalTxs, buildTx(calldata, driver.ContractAddress)) 116 } 117 return internalTxs 118 } 119 120 func (p *DriverTxTransactor) PopInternalTxs(_ iblockproc.BlockCtx, _ iblockproc.BlockState, es iblockproc.EpochState, sealing bool, statedb *state.StateDB) types.Transactions { 121 buildTx := InternalTxBuilder(statedb) 122 internalTxs := make(types.Transactions, 0, 1) 123 // push data into Driver after epoch sealing 124 if sealing { 125 calldata := drivercall.SealEpochValidators(es.Validators.SortedIDs()) 126 internalTxs = append(internalTxs, buildTx(calldata, driver.ContractAddress)) 127 } 128 return internalTxs 129 } 130 131 func (p *DriverTxListener) OnNewReceipt(tx *types.Transaction, r *types.Receipt, originator idx.ValidatorID) { 132 if originator == 0 { 133 return 134 } 135 originatorIdx := p.es.Validators.GetIdx(originator) 136 137 // track originated fee 138 txFee := new(big.Int).Mul(new(big.Int).SetUint64(r.GasUsed), tx.GasPrice()) 139 originated := p.bs.ValidatorStates[originatorIdx].Originated 140 originated.Add(originated, txFee) 141 142 // track gas power refunds 143 notUsedGas := tx.Gas() - r.GasUsed 144 if notUsedGas != 0 { 145 p.bs.ValidatorStates[originatorIdx].DirtyGasRefund += notUsedGas 146 } 147 } 148 149 func decodeDataBytes(l *types.Log) ([]byte, error) { 150 if len(l.Data) < 32 { 151 return nil, io.ErrUnexpectedEOF 152 } 153 start := new(big.Int).SetBytes(l.Data[24:32]).Uint64() 154 if start+32 > uint64(len(l.Data)) { 155 return nil, io.ErrUnexpectedEOF 156 } 157 size := new(big.Int).SetBytes(l.Data[start+24 : start+32]).Uint64() 158 if start+32+size > uint64(len(l.Data)) { 159 return nil, io.ErrUnexpectedEOF 160 } 161 return l.Data[start+32 : start+32+size], nil 162 } 163 164 func (p *DriverTxListener) OnNewLog(l *types.Log) { 165 if l.Address != driver.ContractAddress { 166 return 167 } 168 // Track validator weight changes 169 if l.Topics[0] == driverpos.Topics.UpdateValidatorWeight && len(l.Topics) > 1 && len(l.Data) >= 32 { 170 validatorID := idx.ValidatorID(new(big.Int).SetBytes(l.Topics[1][:]).Uint64()) 171 weight := new(big.Int).SetBytes(l.Data[0:32]) 172 173 if weight.Sign() == 0 { 174 delete(p.bs.NextValidatorProfiles, validatorID) 175 } else { 176 profile, ok := p.bs.NextValidatorProfiles[validatorID] 177 if !ok { 178 profile.PubKey = validatorpk.PubKey{ 179 Type: 0, 180 Raw: []byte{}, 181 } 182 } 183 profile.Weight = weight 184 p.bs.NextValidatorProfiles[validatorID] = profile 185 } 186 } 187 // Track validator pubkey changes 188 if l.Topics[0] == driverpos.Topics.UpdateValidatorPubkey && len(l.Topics) > 1 { 189 validatorID := idx.ValidatorID(new(big.Int).SetBytes(l.Topics[1][:]).Uint64()) 190 pubkey, err := decodeDataBytes(l) 191 if err != nil { 192 log.Warn("Malformed UpdatedValidatorPubkey Driver event") 193 return 194 } 195 196 profile, ok := p.bs.NextValidatorProfiles[validatorID] 197 if !ok { 198 log.Warn("Unexpected UpdatedValidatorPubkey Driver event") 199 return 200 } 201 profile.PubKey, _ = validatorpk.FromBytes(pubkey) 202 p.bs.NextValidatorProfiles[validatorID] = profile 203 } 204 // Update rules 205 if l.Topics[0] == driverpos.Topics.UpdateNetworkRules && len(l.Data) >= 64 { 206 diff, err := decodeDataBytes(l) 207 if err != nil { 208 log.Warn("Malformed UpdateNetworkRules Driver event") 209 return 210 } 211 212 last := &p.es.Rules 213 if p.bs.DirtyRules != nil { 214 last = p.bs.DirtyRules 215 } 216 updated, err := u2u.UpdateRules(*last, diff) 217 if err != nil { 218 log.Warn("Network rules update error", "err", err) 219 return 220 } 221 p.bs.DirtyRules = &updated 222 } 223 // Advance epochs 224 if l.Topics[0] == driverpos.Topics.AdvanceEpochs && len(l.Data) >= 32 { 225 // epochsNum < 2^24 to avoid overflow 226 epochsNum := new(big.Int).SetBytes(l.Data[29:32]).Uint64() 227 228 p.bs.AdvanceEpochs += idx.Epoch(epochsNum) 229 if p.bs.AdvanceEpochs > maxAdvanceEpochs { 230 p.bs.AdvanceEpochs = maxAdvanceEpochs 231 } 232 } 233 } 234 235 func (p *DriverTxListener) Update(bs iblockproc.BlockState, es iblockproc.EpochState) { 236 p.bs, p.es = bs, es 237 } 238 239 func (p *DriverTxListener) Finalize() iblockproc.BlockState { 240 return p.bs 241 }