natspec.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package natspec
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/robertkrimen/otto"
  6. "strings"
  7. "github.com/ethereum/go-ethereum/common"
  8. "github.com/ethereum/go-ethereum/crypto"
  9. )
  10. type abi2method map[[8]byte]*method
  11. type NatSpec struct {
  12. jsvm *otto.Otto
  13. methods abi2method
  14. userDocJson, abiDocJson []byte
  15. userDoc userDoc
  16. // abiDoc abiDoc
  17. }
  18. // TODO: should initialise with abi and userdoc jsons
  19. func New() (self *NatSpec, err error) {
  20. // fetch abi, userdoc
  21. abi := []byte("")
  22. userdoc := []byte("")
  23. return NewWithDocs(abi, userdoc)
  24. }
  25. func NewWithDocs(abiDocJson, userDocJson []byte) (self *NatSpec, err error) {
  26. self = &NatSpec{
  27. jsvm: otto.New(),
  28. abiDocJson: abiDocJson,
  29. userDocJson: userDocJson,
  30. }
  31. _, err = self.jsvm.Run(natspecJS)
  32. if err != nil {
  33. return
  34. }
  35. _, err = self.jsvm.Run("var natspec = require('natspec');")
  36. if err != nil {
  37. return
  38. }
  39. err = json.Unmarshal(userDocJson, &self.userDoc)
  40. // err = parseAbiJson(abiDocJson, &self.abiDoc)
  41. return
  42. }
  43. // type abiDoc []method
  44. // type method struct {
  45. // Name string `json:name`
  46. // Inputs []input `json:inputs`
  47. // abiKey [8]byte
  48. // }
  49. // type input struct {
  50. // Name string `json:name`
  51. // Type string `json:type`
  52. // }
  53. type method struct {
  54. Notice string `json:notice`
  55. name string
  56. }
  57. type userDoc struct {
  58. Methods map[string]*method `json:methods`
  59. }
  60. func (self *NatSpec) makeAbi2method(abiKey [8]byte) (meth *method) {
  61. if self.methods != nil {
  62. meth = self.methods[abiKey]
  63. return
  64. }
  65. self.methods = make(abi2method)
  66. for signature, m := range self.userDoc.Methods {
  67. name := strings.Split(signature, "(")[0]
  68. hash := []byte(common.Bytes2Hex(crypto.Sha3([]byte(signature))))
  69. var key [8]byte
  70. copy(key[:], hash[:8])
  71. self.methods[key] = meth
  72. meth.name = name
  73. if key == abiKey {
  74. meth = m
  75. }
  76. }
  77. return
  78. }
  79. func (self *NatSpec) Notice(tx string, abi string) (notice string, err error) {
  80. var abiKey [8]byte
  81. copy(abiKey[:], []byte(abi)[:8])
  82. meth := self.makeAbi2method(abiKey)
  83. if meth == nil {
  84. err = fmt.Errorf("abi key %x does not match any method %v")
  85. return
  86. }
  87. notice, err = self.noticeForMethod(tx, meth.name, meth.Notice)
  88. return
  89. }
  90. func (self *NatSpec) noticeForMethod(tx string, name, expression string) (notice string, err error) {
  91. if _, err = self.jsvm.Run("var transaction = " + tx + ";"); err != nil {
  92. return "", fmt.Errorf("natspec.js error setting transaction: %v", err)
  93. }
  94. if _, err = self.jsvm.Run("var abi = " + string(self.abiDocJson) + ";"); err != nil {
  95. return "", fmt.Errorf("natspec.js error setting abi: %v", err)
  96. }
  97. if _, err = self.jsvm.Run("var method = '" + name + "';"); err != nil {
  98. return "", fmt.Errorf("natspec.js error setting method: %v", err)
  99. }
  100. if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil {
  101. return "", fmt.Errorf("natspec.js error setting expression: %v", err)
  102. }
  103. self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};")
  104. value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);")
  105. if err != nil {
  106. return "", fmt.Errorf("natspec.js error evaluating expression: %v", err)
  107. }
  108. evalError := "Natspec evaluation failed, wrong input params"
  109. if value.String() == evalError {
  110. return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression)
  111. }
  112. if len(value.String()) == 0 {
  113. return "", fmt.Errorf("natspec.js error evaluating expression")
  114. }
  115. return value.String(), nil
  116. }