contracts_lightclient.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package vm
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "github.com/coredao-org/btcpowermirror/lightmirror"
  7. "github.com/ethereum/go-ethereum/common"
  8. "github.com/ethereum/go-ethereum/params"
  9. )
  10. const (
  11. uint64TypeLength uint64 = 8
  12. precompileContractInputMetaDataLength uint64 = 32
  13. )
  14. // btcValidate implemented as a precompiled contract.
  15. type btcValidate struct{}
  16. func (c *btcValidate) RequiredGas(input []byte) uint64 {
  17. return params.BitcoinHeaderValidateGas + uint64(len(input)/32)*params.IAVLMerkleProofValidateGas
  18. }
  19. func (c *btcValidate) Run(input []byte) (result []byte, err error) {
  20. defer func() {
  21. if r := recover(); r != nil {
  22. err = fmt.Errorf("internal error: %v\n", r)
  23. }
  24. }()
  25. if uint64(len(input)) <= precompileContractInputMetaDataLength {
  26. return nil, fmt.Errorf("invalid input")
  27. }
  28. payloadLength := binary.BigEndian.Uint64(input[precompileContractInputMetaDataLength-uint64TypeLength : precompileContractInputMetaDataLength])
  29. if uint64(len(input)) != payloadLength+precompileContractInputMetaDataLength {
  30. return nil, fmt.Errorf("invalid input: input size should be %d, actual size is %d", payloadLength+precompileContractInputMetaDataLength, len(input))
  31. }
  32. rbuf := bytes.NewReader(input[precompileContractInputMetaDataLength:])
  33. var mirror lightmirror.BtcLightMirror
  34. err = mirror.Deserialize(rbuf)
  35. if err != nil {
  36. err = fmt.Errorf("deserialize btcLightMirror failed %s", err.Error())
  37. return nil, err
  38. }
  39. // Verify MerkleRoot & coinbaseTx
  40. err = mirror.CheckMerkle()
  41. if err != nil {
  42. err = fmt.Errorf("verify btcLightMirror failed %s", err.Error())
  43. return nil, err
  44. }
  45. coinbaseAddr, addrType := mirror.GetCoinbaseAddress()
  46. // result
  47. // | coinbaseAddr |
  48. // | 20 bytes + 12 bytes |
  49. addrTypeBytes := make([]byte, 4)
  50. binary.BigEndian.PutUint32(addrTypeBytes, (uint32)(addrType))
  51. addrTypeBytes = common.LeftPadBytes(addrTypeBytes[:], 32)
  52. return append(common.RightPadBytes(coinbaseAddr[:], 32), addrTypeBytes...), nil
  53. }
  54. // btcValidateV2 implemented as a precompiled contract.
  55. type btcValidateV2 struct{}
  56. func (c *btcValidateV2) RequiredGas(input []byte) uint64 {
  57. return params.BitcoinHeaderValidateGas + uint64(len(input)/32)*params.IAVLMerkleProofValidateGas
  58. }
  59. func (c *btcValidateV2) Run(input []byte) (result []byte, err error) {
  60. defer func() {
  61. if r := recover(); r != nil {
  62. err = fmt.Errorf("internal error: %v\n", r)
  63. }
  64. }()
  65. if uint64(len(input)) <= precompileContractInputMetaDataLength {
  66. return nil, fmt.Errorf("invalid input")
  67. }
  68. payloadLength := binary.BigEndian.Uint64(input[precompileContractInputMetaDataLength-uint64TypeLength : precompileContractInputMetaDataLength])
  69. if uint64(len(input)) != payloadLength+precompileContractInputMetaDataLength {
  70. return nil, fmt.Errorf("invalid input: input size should be %d, actual size is %d", payloadLength+precompileContractInputMetaDataLength, len(input))
  71. }
  72. rbuf := bytes.NewReader(input[precompileContractInputMetaDataLength:])
  73. var mirror lightmirror.BtcLightMirrorV2
  74. err = mirror.Deserialize(rbuf)
  75. if err != nil {
  76. err = fmt.Errorf("deserialize BtcLightMirrorV2 failed %s", err.Error())
  77. return nil, err
  78. }
  79. // Verify MerkleRoot & coinbaseTx
  80. err = mirror.CheckMerkle()
  81. if err != nil {
  82. err = fmt.Errorf("verify BtcLightMirrorV2 failed %s", err.Error())
  83. return nil, err
  84. }
  85. candidateAddr, rewardAddr, blockHash := mirror.ParsePowerParams()
  86. res := make([]byte, 0, 96)
  87. res = append(res, common.LeftPadBytes(candidateAddr.Bytes(), 32)...)
  88. res = append(res, common.LeftPadBytes(rewardAddr.Bytes(), 32)...)
  89. res = append(res, blockHash[:]...)
  90. return res, nil
  91. }