github.com/phillinzzz/newBsc@v1.1.6/core/vm/contracts_lightclient.go (about)

     1  package vm
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  
     7  	"github.com/phillinzzz/newBsc/core/vm/lightclient"
     8  	"github.com/phillinzzz/newBsc/params"
     9  )
    10  
    11  const (
    12  	uint64TypeLength                      uint64 = 8
    13  	precompileContractInputMetaDataLength uint64 = 32
    14  	consensusStateLengthBytesLength       uint64 = 32
    15  
    16  	tmHeaderValidateResultMetaDataLength uint64 = 32
    17  	merkleProofValidateResultLength      uint64 = 32
    18  )
    19  
    20  // input:
    21  // consensus state length | consensus state | tendermint header |
    22  // 32 bytes               |                 |                   |
    23  func decodeTendermintHeaderValidationInput(input []byte) (*lightclient.ConsensusState, *lightclient.Header, error) {
    24  	csLen := binary.BigEndian.Uint64(input[consensusStateLengthBytesLength-uint64TypeLength : consensusStateLengthBytesLength])
    25  	if uint64(len(input)) <= consensusStateLengthBytesLength+csLen {
    26  		return nil, nil, fmt.Errorf("expected payload size %d, actual size: %d", consensusStateLengthBytesLength+csLen, len(input))
    27  	}
    28  
    29  	cs, err := lightclient.DecodeConsensusState(input[consensusStateLengthBytesLength : consensusStateLengthBytesLength+csLen])
    30  	if err != nil {
    31  		return nil, nil, err
    32  	}
    33  	header, err := lightclient.DecodeHeader(input[consensusStateLengthBytesLength+csLen:])
    34  	if err != nil {
    35  		return nil, nil, err
    36  	}
    37  
    38  	return &cs, header, nil
    39  }
    40  
    41  // tmHeaderValidate implemented as a native contract.
    42  type tmHeaderValidate struct{}
    43  
    44  func (c *tmHeaderValidate) RequiredGas(input []byte) uint64 {
    45  	return params.TendermintHeaderValidateGas
    46  }
    47  
    48  func (c *tmHeaderValidate) Run(input []byte) (result []byte, err error) {
    49  	defer func() {
    50  		if r := recover(); r != nil {
    51  			err = fmt.Errorf("internal error: %v\n", r)
    52  		}
    53  	}()
    54  
    55  	if uint64(len(input)) <= precompileContractInputMetaDataLength {
    56  		return nil, fmt.Errorf("invalid input")
    57  	}
    58  
    59  	payloadLength := binary.BigEndian.Uint64(input[precompileContractInputMetaDataLength-uint64TypeLength : precompileContractInputMetaDataLength])
    60  	if uint64(len(input)) != payloadLength+precompileContractInputMetaDataLength {
    61  		return nil, fmt.Errorf("invalid input: input size should be %d, actual the size is %d", payloadLength+precompileContractInputMetaDataLength, len(input))
    62  	}
    63  
    64  	cs, header, err := decodeTendermintHeaderValidationInput(input[precompileContractInputMetaDataLength:])
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	validatorSetChanged, err := cs.ApplyHeader(header)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	consensusStateBytes, err := cs.EncodeConsensusState()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// result
    80  	// | validatorSetChanged | empty      | consensusStateBytesLength |  new consensusState |
    81  	// | 1 byte              | 23 bytes   | 8 bytes                   |                     |
    82  	lengthBytes := make([]byte, tmHeaderValidateResultMetaDataLength)
    83  	if validatorSetChanged {
    84  		copy(lengthBytes[:1], []byte{0x01})
    85  	}
    86  	consensusStateBytesLength := uint64(len(consensusStateBytes))
    87  	binary.BigEndian.PutUint64(lengthBytes[tmHeaderValidateResultMetaDataLength-uint64TypeLength:], consensusStateBytesLength)
    88  
    89  	result = append(lengthBytes, consensusStateBytes...)
    90  
    91  	return result, nil
    92  }
    93  
    94  //------------------------------------------------------------------------------------------------------------------------------------------------
    95  
    96  // tmHeaderValidate implemented as a native contract.
    97  type iavlMerkleProofValidate struct{}
    98  
    99  func (c *iavlMerkleProofValidate) RequiredGas(input []byte) uint64 {
   100  	return params.IAVLMerkleProofValidateGas
   101  }
   102  
   103  // input:
   104  // | payload length | payload    |
   105  // | 32 bytes       |            |
   106  func (c *iavlMerkleProofValidate) Run(input []byte) (result []byte, err error) {
   107  	defer func() {
   108  		if r := recover(); r != nil {
   109  			err = fmt.Errorf("internal error: %v\n", r)
   110  		}
   111  	}()
   112  
   113  	if uint64(len(input)) <= precompileContractInputMetaDataLength {
   114  		return nil, fmt.Errorf("invalid input: input should include %d bytes payload length and payload", precompileContractInputMetaDataLength)
   115  	}
   116  
   117  	payloadLength := binary.BigEndian.Uint64(input[precompileContractInputMetaDataLength-uint64TypeLength : precompileContractInputMetaDataLength])
   118  	if uint64(len(input)) != payloadLength+precompileContractInputMetaDataLength {
   119  		return nil, fmt.Errorf("invalid input: input size should be %d, actual the size is %d", payloadLength+precompileContractInputMetaDataLength, len(input))
   120  	}
   121  
   122  	kvmp, err := lightclient.DecodeKeyValueMerkleProof(input[precompileContractInputMetaDataLength:])
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	valid := kvmp.Validate()
   128  	if !valid {
   129  		return nil, fmt.Errorf("invalid merkle proof")
   130  	}
   131  
   132  	result = make([]byte, merkleProofValidateResultLength)
   133  	binary.BigEndian.PutUint64(result[merkleProofValidateResultLength-uint64TypeLength:], 0x01)
   134  	return result, nil
   135  }