github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/consensus/bor/heimdall/span/spanner.go (about) 1 package span 2 3 import ( 4 "context" 5 "encoding/hex" 6 "math" 7 "math/big" 8 9 "github.com/ethereum/go-ethereum/common" 10 "github.com/ethereum/go-ethereum/common/hexutil" 11 "github.com/ethereum/go-ethereum/consensus/bor/abi" 12 "github.com/ethereum/go-ethereum/consensus/bor/api" 13 "github.com/ethereum/go-ethereum/consensus/bor/statefull" 14 "github.com/ethereum/go-ethereum/consensus/bor/valset" 15 "github.com/ethereum/go-ethereum/core" 16 "github.com/ethereum/go-ethereum/core/state" 17 "github.com/ethereum/go-ethereum/core/types" 18 "github.com/ethereum/go-ethereum/internal/ethapi" 19 "github.com/ethereum/go-ethereum/log" 20 "github.com/ethereum/go-ethereum/params" 21 "github.com/ethereum/go-ethereum/rlp" 22 "github.com/ethereum/go-ethereum/rpc" 23 ) 24 25 type ChainSpanner struct { 26 ethAPI api.Caller 27 validatorSet abi.ABI 28 chainConfig *params.ChainConfig 29 validatorContractAddress common.Address 30 } 31 32 func NewChainSpanner(ethAPI api.Caller, validatorSet abi.ABI, chainConfig *params.ChainConfig, validatorContractAddress common.Address) *ChainSpanner { 33 return &ChainSpanner{ 34 ethAPI: ethAPI, 35 validatorSet: validatorSet, 36 chainConfig: chainConfig, 37 validatorContractAddress: validatorContractAddress, 38 } 39 } 40 41 // GetCurrentSpan get current span from contract 42 func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Hash) (*Span, error) { 43 // block 44 blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false) 45 46 // method 47 const method = "getCurrentSpan" 48 49 data, err := c.validatorSet.Pack(method) 50 if err != nil { 51 log.Error("Unable to pack tx for getCurrentSpan", "error", err) 52 53 return nil, err 54 } 55 56 msgData := (hexutil.Bytes)(data) 57 toAddress := c.validatorContractAddress 58 gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) 59 60 // todo: would we like to have a timeout here? 61 result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ 62 Gas: &gas, 63 To: &toAddress, 64 Data: &msgData, 65 }, blockNr, nil) 66 if err != nil { 67 return nil, err 68 } 69 70 // span result 71 ret := new(struct { 72 Number *big.Int 73 StartBlock *big.Int 74 EndBlock *big.Int 75 }) 76 77 if err := c.validatorSet.UnpackIntoInterface(ret, method, result); err != nil { 78 return nil, err 79 } 80 81 // create new span 82 span := Span{ 83 ID: ret.Number.Uint64(), 84 StartBlock: ret.StartBlock.Uint64(), 85 EndBlock: ret.EndBlock.Uint64(), 86 } 87 88 return &span, nil 89 } 90 91 // GetCurrentValidators get current validators 92 func (c *ChainSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error) { 93 ctx, cancel := context.WithCancel(ctx) 94 defer cancel() 95 96 // method 97 const method = "getBorValidators" 98 99 data, err := c.validatorSet.Pack(method, big.NewInt(0).SetUint64(blockNumber)) 100 if err != nil { 101 log.Error("Unable to pack tx for getValidator", "error", err) 102 return nil, err 103 } 104 105 // call 106 msgData := (hexutil.Bytes)(data) 107 toAddress := c.validatorContractAddress 108 gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) 109 110 result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ 111 Gas: &gas, 112 To: &toAddress, 113 Data: &msgData, 114 }, blockNrOrHash, nil) 115 if err != nil { 116 return nil, err 117 } 118 119 var ( 120 ret0 = new([]common.Address) 121 ret1 = new([]*big.Int) 122 ) 123 124 out := &[]interface{}{ 125 ret0, 126 ret1, 127 } 128 129 if err := c.validatorSet.UnpackIntoInterface(out, method, result); err != nil { 130 return nil, err 131 } 132 133 valz := make([]*valset.Validator, len(*ret0)) 134 for i, a := range *ret0 { 135 valz[i] = &valset.Validator{ 136 Address: a, 137 VotingPower: (*ret1)[i].Int64(), 138 } 139 } 140 141 return valz, nil 142 } 143 144 func (c *ChainSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { 145 blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false) 146 147 return c.GetCurrentValidatorsByBlockNrOrHash(ctx, blockNr, blockNumber) 148 } 149 150 const method = "commitSpan" 151 152 func (c *ChainSpanner) CommitSpan(ctx context.Context, heimdallSpan HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error { 153 // get validators bytes 154 validators := make([]valset.MinimalVal, 0, len(heimdallSpan.ValidatorSet.Validators)) 155 for _, val := range heimdallSpan.ValidatorSet.Validators { 156 validators = append(validators, val.MinimalVal()) 157 } 158 159 validatorBytes, err := rlp.EncodeToBytes(validators) 160 if err != nil { 161 return err 162 } 163 164 // get producers bytes 165 producers := make([]valset.MinimalVal, 0, len(heimdallSpan.SelectedProducers)) 166 for _, val := range heimdallSpan.SelectedProducers { 167 producers = append(producers, val.MinimalVal()) 168 } 169 170 producerBytes, err := rlp.EncodeToBytes(producers) 171 if err != nil { 172 return err 173 } 174 175 log.Info("✅ Committing new span", 176 "id", heimdallSpan.ID, 177 "startBlock", heimdallSpan.StartBlock, 178 "endBlock", heimdallSpan.EndBlock, 179 "validatorBytes", hex.EncodeToString(validatorBytes), 180 "producerBytes", hex.EncodeToString(producerBytes), 181 ) 182 183 data, err := c.validatorSet.Pack(method, 184 big.NewInt(0).SetUint64(heimdallSpan.ID), 185 big.NewInt(0).SetUint64(heimdallSpan.StartBlock), 186 big.NewInt(0).SetUint64(heimdallSpan.EndBlock), 187 validatorBytes, 188 producerBytes, 189 ) 190 if err != nil { 191 log.Error("Unable to pack tx for commitSpan", "error", err) 192 193 return err 194 } 195 196 // get system message 197 msg := statefull.GetSystemMessage(c.validatorContractAddress, data) 198 199 // apply message 200 _, err = statefull.ApplyMessage(ctx, msg, state, header, c.chainConfig, chainContext) 201 202 return err 203 }