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  }