| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- package vm
- import (
- "encoding/binary"
- "fmt"
- "github.com/ethereum/go-ethereum/core/vm/lightclient"
- "github.com/ethereum/go-ethereum/params"
- )
- const (
- precompileContractInputMetaDataLength uint64 = 32
- consensusStateLengthBytesLength uint64 = 32
- tmHeaderValidateResultMetaDataLength uint64 = 32
- merkleProofValidateResultLength uint64 = 32
- )
- // input:
- // consensus state length | consensus state | tendermint header |
- // 32 bytes | | |
- func decodeTendermintHeaderValidationInput(input []byte) (*lightclient.ConsensusState, *lightclient.Header, error) {
- csLen := binary.BigEndian.Uint64(input[consensusStateLengthBytesLength-8 : consensusStateLengthBytesLength])
- if uint64(len(input)) <= consensusStateLengthBytesLength+csLen {
- return nil, nil, fmt.Errorf("expected payload size %d, actual size: %d", consensusStateLengthBytesLength+csLen, len(input))
- }
- cs, err := lightclient.DecodeConsensusState(input[consensusStateLengthBytesLength : consensusStateLengthBytesLength+csLen])
- if err != nil {
- return nil, nil, err
- }
- header, err := lightclient.DecodeHeader(input[consensusStateLengthBytesLength+csLen:])
- if err != nil {
- return nil, nil, err
- }
- return &cs, header, nil
- }
- // tmHeaderValidate implemented as a native contract.
- type tmHeaderValidate struct{}
- func (c *tmHeaderValidate) RequiredGas(input []byte) uint64 {
- return params.TendermintHeaderValidateGas
- }
- func (c *tmHeaderValidate) Run(input []byte) (result []byte, err error) {
- defer func() {
- if r := recover(); r != nil {
- err = fmt.Errorf("internal error: %v\n", r)
- }
- }()
- if uint64(len(input)) <= precompileContractInputMetaDataLength {
- return nil, fmt.Errorf("invalid input")
- }
- payloadLength := binary.BigEndian.Uint64(input[precompileContractInputMetaDataLength-8 : precompileContractInputMetaDataLength])
- if uint64(len(input)) != payloadLength+precompileContractInputMetaDataLength {
- return nil, fmt.Errorf("invalid input: input size should be %d, actual the size is %d", payloadLength+precompileContractInputMetaDataLength, len(input))
- }
- cs, header, err := decodeTendermintHeaderValidationInput(input[precompileContractInputMetaDataLength:])
- if err != nil {
- return nil, err
- }
- validatorSetChanged, err := cs.ApplyHeader(header)
- if err != nil {
- return nil, err
- }
- consensusStateBytes, err := cs.EncodeConsensusState()
- if err != nil {
- return nil, err
- }
- // result
- // | validatorSetChanged | empty | consensusStateBytesLength | new consensusState |
- // | 1 byte | 23 bytes | 8 bytes | |
- lengthBytes := make([]byte, tmHeaderValidateResultMetaDataLength)
- if validatorSetChanged {
- copy(lengthBytes[:1], []byte{0x01})
- }
- consensusStateBytesLength := uint64(len(consensusStateBytes))
- binary.BigEndian.PutUint64(lengthBytes[tmHeaderValidateResultMetaDataLength-8:], consensusStateBytesLength)
- result = append(lengthBytes, consensusStateBytes...)
- return result, nil
- }
- //------------------------------------------------------------------------------------------------------------------------------------------------
- // tmHeaderValidate implemented as a native contract.
- type iavlMerkleProofValidate struct{}
- func (c *iavlMerkleProofValidate) RequiredGas(input []byte) uint64 {
- return params.IAVLMerkleProofValidateGas
- }
- // input:
- // | payload length | payload |
- // | 32 bytes | |
- func (c *iavlMerkleProofValidate) Run(input []byte) (result []byte, err error) {
- defer func() {
- if r := recover(); r != nil {
- err = fmt.Errorf("internal error: %v\n", r)
- }
- }()
- if uint64(len(input)) <= precompileContractInputMetaDataLength {
- return nil, fmt.Errorf("invalid input: input should include %d bytes payload length and payload", precompileContractInputMetaDataLength)
- }
- payloadLength := binary.BigEndian.Uint64(input[precompileContractInputMetaDataLength-8 : precompileContractInputMetaDataLength])
- if uint64(len(input)) != payloadLength+precompileContractInputMetaDataLength {
- return nil, fmt.Errorf("invalid input: input size should be %d, actual the size is %d", payloadLength+precompileContractInputMetaDataLength, len(input))
- }
- kvmp, err := lightclient.DecodeKeyValueMerkleProof(input[precompileContractInputMetaDataLength:])
- if err != nil {
- return nil, err
- }
- valid := kvmp.Validate()
- if !valid {
- return nil, fmt.Errorf("invalid merkle proof")
- }
- result = make([]byte, merkleProofValidateResultLength)
- binary.BigEndian.PutUint64(result[merkleProofValidateResultLength-8:], 0x01)
- return result, nil
- }
|