contracts_lightclient.go 4.6 KB

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