contracts_lightclient.go 4.5 KB

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