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 }