github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/signer/rules/rules.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:42</date>
    10  //</624450110876553216>
    11  
    12  
    13  package rules
    14  
    15  import (
    16  	"encoding/json"
    17  	"fmt"
    18  	"os"
    19  	"strings"
    20  
    21  	"github.com/ethereum/go-ethereum/common"
    22  	"github.com/ethereum/go-ethereum/internal/ethapi"
    23  	"github.com/ethereum/go-ethereum/log"
    24  	"github.com/ethereum/go-ethereum/signer/core"
    25  	"github.com/ethereum/go-ethereum/signer/rules/deps"
    26  	"github.com/ethereum/go-ethereum/signer/storage"
    27  	"github.com/robertkrimen/otto"
    28  )
    29  
    30  var (
    31  	BigNumber_JS = deps.MustAsset("bignumber.js")
    32  )
    33  
    34  //consoleoutput是console.log和console.error方法的重写,用于
    35  //将输出流传输到配置的输出流,而不是stdout。
    36  func consoleOutput(call otto.FunctionCall) otto.Value {
    37  	output := []string{"JS:> "}
    38  	for _, argument := range call.ArgumentList {
    39  		output = append(output, fmt.Sprintf("%v", argument))
    40  	}
    41  	fmt.Fprintln(os.Stdout, strings.Join(output, " "))
    42  	return otto.Value{}
    43  }
    44  
    45  //rulesetui提供了一个signerui的实现,它评估一个javascript
    46  //每个定义的UI方法的文件
    47  type rulesetUI struct {
    48  next        core.SignerUI //下一个处理程序,用于手动处理
    49  	storage     storage.Storage
    50  	credentials storage.Storage
    51  jsRules     string //使用的规则
    52  }
    53  
    54  func NewRuleEvaluator(next core.SignerUI, jsbackend, credentialsBackend storage.Storage) (*rulesetUI, error) {
    55  	c := &rulesetUI{
    56  		next:        next,
    57  		storage:     jsbackend,
    58  		credentials: credentialsBackend,
    59  		jsRules:     "",
    60  	}
    61  
    62  	return c, nil
    63  }
    64  
    65  func (r *rulesetUI) Init(javascriptRules string) error {
    66  	r.jsRules = javascriptRules
    67  	return nil
    68  }
    69  func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error) {
    70  
    71  //每次实例化一个新的VM引擎
    72  	vm := otto.New()
    73  //设置本机回调
    74  	consoleObj, _ := vm.Get("console")
    75  	consoleObj.Object().Set("log", consoleOutput)
    76  	consoleObj.Object().Set("error", consoleOutput)
    77  	vm.Set("storage", r.storage)
    78  
    79  //加载引导程序库
    80  	script, err := vm.Compile("bignumber.js", BigNumber_JS)
    81  	if err != nil {
    82  		log.Warn("Failed loading libraries", "err", err)
    83  		return otto.UndefinedValue(), err
    84  	}
    85  	vm.Run(script)
    86  
    87  //运行实际规则实现
    88  	_, err = vm.Run(r.jsRules)
    89  	if err != nil {
    90  		log.Warn("Execution failed", "err", err)
    91  		return otto.UndefinedValue(), err
    92  	}
    93  
    94  //和实际通话
    95  //所有调用都是对象,其中参数是该对象中的键。
    96  //为了在JS和Go之间提供额外的隔离,我们在Go端将其序列化为JSON,
    97  //并在JS端对其进行反序列化。
    98  
    99  	jsonbytes, err := json.Marshal(jsarg)
   100  	if err != nil {
   101  		log.Warn("failed marshalling data", "data", jsarg)
   102  		return otto.UndefinedValue(), err
   103  	}
   104  //现在,我们称之为foobar(json.parse(<jsondata>)。
   105  	var call string
   106  	if len(jsonbytes) > 0 {
   107  		call = fmt.Sprintf("%v(JSON.parse(%v))", jsfunc, string(jsonbytes))
   108  	} else {
   109  		call = fmt.Sprintf("%v()", jsfunc)
   110  	}
   111  	return vm.Run(call)
   112  }
   113  
   114  func (r *rulesetUI) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) {
   115  	if err != nil {
   116  		return false, err
   117  	}
   118  	v, err := r.execute(jsfunc, string(jsarg))
   119  	if err != nil {
   120  		log.Info("error occurred during execution", "error", err)
   121  		return false, err
   122  	}
   123  	result, err := v.ToString()
   124  	if err != nil {
   125  		log.Info("error occurred during response unmarshalling", "error", err)
   126  		return false, err
   127  	}
   128  	if result == "Approve" {
   129  		log.Info("Op approved")
   130  		return true, nil
   131  	} else if result == "Reject" {
   132  		log.Info("Op rejected")
   133  		return false, nil
   134  	}
   135  	return false, fmt.Errorf("Unknown response")
   136  }
   137  
   138  func (r *rulesetUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
   139  	jsonreq, err := json.Marshal(request)
   140  	approved, err := r.checkApproval("ApproveTx", jsonreq, err)
   141  	if err != nil {
   142  		log.Info("Rule-based approval error, going to manual", "error", err)
   143  		return r.next.ApproveTx(request)
   144  	}
   145  
   146  	if approved {
   147  		return core.SignTxResponse{
   148  				Transaction: request.Transaction,
   149  				Approved:    true,
   150  				Password:    r.lookupPassword(request.Transaction.From.Address()),
   151  			},
   152  			nil
   153  	}
   154  	return core.SignTxResponse{Approved: false}, err
   155  }
   156  
   157  func (r *rulesetUI) lookupPassword(address common.Address) string {
   158  	return r.credentials.Get(strings.ToLower(address.String()))
   159  }
   160  
   161  func (r *rulesetUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
   162  	jsonreq, err := json.Marshal(request)
   163  	approved, err := r.checkApproval("ApproveSignData", jsonreq, err)
   164  	if err != nil {
   165  		log.Info("Rule-based approval error, going to manual", "error", err)
   166  		return r.next.ApproveSignData(request)
   167  	}
   168  	if approved {
   169  		return core.SignDataResponse{Approved: true, Password: r.lookupPassword(request.Address.Address())}, nil
   170  	}
   171  	return core.SignDataResponse{Approved: false, Password: ""}, err
   172  }
   173  
   174  func (r *rulesetUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
   175  	jsonreq, err := json.Marshal(request)
   176  	approved, err := r.checkApproval("ApproveExport", jsonreq, err)
   177  	if err != nil {
   178  		log.Info("Rule-based approval error, going to manual", "error", err)
   179  		return r.next.ApproveExport(request)
   180  	}
   181  	if approved {
   182  		return core.ExportResponse{Approved: true}, nil
   183  	}
   184  	return core.ExportResponse{Approved: false}, err
   185  }
   186  
   187  func (r *rulesetUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
   188  //这不能由规则处理,需要设置密码
   189  //发送到下一个
   190  	return r.next.ApproveImport(request)
   191  }
   192  
   193  //规则未处理OnInputRequired
   194  func (r *rulesetUI) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) {
   195  	return r.next.OnInputRequired(info)
   196  }
   197  
   198  func (r *rulesetUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
   199  	jsonreq, err := json.Marshal(request)
   200  	approved, err := r.checkApproval("ApproveListing", jsonreq, err)
   201  	if err != nil {
   202  		log.Info("Rule-based approval error, going to manual", "error", err)
   203  		return r.next.ApproveListing(request)
   204  	}
   205  	if approved {
   206  		return core.ListResponse{Accounts: request.Accounts}, nil
   207  	}
   208  	return core.ListResponse{}, err
   209  }
   210  
   211  func (r *rulesetUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
   212  //这不能由规则处理,需要设置密码
   213  //发送到下一个
   214  	return r.next.ApproveNewAccount(request)
   215  }
   216  
   217  func (r *rulesetUI) ShowError(message string) {
   218  	log.Error(message)
   219  	r.next.ShowError(message)
   220  }
   221  
   222  func (r *rulesetUI) ShowInfo(message string) {
   223  	log.Info(message)
   224  	r.next.ShowInfo(message)
   225  }
   226  
   227  func (r *rulesetUI) OnSignerStartup(info core.StartupInfo) {
   228  	jsonInfo, err := json.Marshal(info)
   229  	if err != nil {
   230  		log.Warn("failed marshalling data", "data", info)
   231  		return
   232  	}
   233  	r.next.OnSignerStartup(info)
   234  	_, err = r.execute("OnSignerStartup", string(jsonInfo))
   235  	if err != nil {
   236  		log.Info("error occurred during execution", "error", err)
   237  	}
   238  }
   239  
   240  func (r *rulesetUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
   241  	jsonTx, err := json.Marshal(tx)
   242  	if err != nil {
   243  		log.Warn("failed marshalling transaction", "tx", tx)
   244  		return
   245  	}
   246  	_, err = r.execute("OnApprovedTx", string(jsonTx))
   247  	if err != nil {
   248  		log.Info("error occurred during execution", "error", err)
   249  	}
   250  }
   251