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  }