| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package natspec
- import (
- "encoding/json"
- "fmt"
- "github.com/robertkrimen/otto"
- "strings"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- )
- type abi2method map[[8]byte]*method
- type NatSpec struct {
- jsvm *otto.Otto
- methods abi2method
- userDocJson, abiDocJson []byte
- userDoc userDoc
- // abiDoc abiDoc
- }
- // TODO: should initialise with abi and userdoc jsons
- func New() (self *NatSpec, err error) {
- // fetch abi, userdoc
- abi := []byte("")
- userdoc := []byte("")
- return NewWithDocs(abi, userdoc)
- }
- func NewWithDocs(abiDocJson, userDocJson []byte) (self *NatSpec, err error) {
- self = &NatSpec{
- jsvm: otto.New(),
- abiDocJson: abiDocJson,
- userDocJson: userDocJson,
- }
- _, err = self.jsvm.Run(natspecJS)
- if err != nil {
- return
- }
- _, err = self.jsvm.Run("var natspec = require('natspec');")
- if err != nil {
- return
- }
- err = json.Unmarshal(userDocJson, &self.userDoc)
- // err = parseAbiJson(abiDocJson, &self.abiDoc)
- return
- }
- // type abiDoc []method
- // type method struct {
- // Name string `json:name`
- // Inputs []input `json:inputs`
- // abiKey [8]byte
- // }
- // type input struct {
- // Name string `json:name`
- // Type string `json:type`
- // }
- type method struct {
- Notice string `json:notice`
- name string
- }
- type userDoc struct {
- Methods map[string]*method `json:methods`
- }
- func (self *NatSpec) makeAbi2method(abiKey [8]byte) (meth *method) {
- if self.methods != nil {
- meth = self.methods[abiKey]
- return
- }
- self.methods = make(abi2method)
- for signature, m := range self.userDoc.Methods {
- name := strings.Split(signature, "(")[0]
- hash := []byte(common.Bytes2Hex(crypto.Sha3([]byte(signature))))
- var key [8]byte
- copy(key[:], hash[:8])
- self.methods[key] = meth
- meth.name = name
- if key == abiKey {
- meth = m
- }
- }
- return
- }
- func (self *NatSpec) Notice(tx string, abi string) (notice string, err error) {
- var abiKey [8]byte
- copy(abiKey[:], []byte(abi)[:8])
- meth := self.makeAbi2method(abiKey)
- if meth == nil {
- err = fmt.Errorf("abi key %x does not match any method %v")
- return
- }
- notice, err = self.noticeForMethod(tx, meth.name, meth.Notice)
- return
- }
- func (self *NatSpec) noticeForMethod(tx string, name, expression string) (notice string, err error) {
- if _, err = self.jsvm.Run("var transaction = " + tx + ";"); err != nil {
- return "", fmt.Errorf("natspec.js error setting transaction: %v", err)
- }
- if _, err = self.jsvm.Run("var abi = " + string(self.abiDocJson) + ";"); err != nil {
- return "", fmt.Errorf("natspec.js error setting abi: %v", err)
- }
- if _, err = self.jsvm.Run("var method = '" + name + "';"); err != nil {
- return "", fmt.Errorf("natspec.js error setting method: %v", err)
- }
- if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil {
- return "", fmt.Errorf("natspec.js error setting expression: %v", err)
- }
- self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};")
- value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);")
- if err != nil {
- return "", fmt.Errorf("natspec.js error evaluating expression: %v", err)
- }
- evalError := "Natspec evaluation failed, wrong input params"
- if value.String() == evalError {
- return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression)
- }
- if len(value.String()) == 0 {
- return "", fmt.Errorf("natspec.js error evaluating expression")
- }
- return value.String(), nil
- }
|