contracts_lightclient.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  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. }