github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/eth/tracers/tracer.go (about)

     1  // Copyright 2016 The Spectrum Authors
     2  // This file is part of the Spectrum library.
     3  //
     4  // The Spectrum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The Spectrum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tracers
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"github.com/SmartMeshFoundation/Spectrum/eth/tracers/internal/tracers"
    25  	"math/big"
    26  	"strings"
    27  	"sync/atomic"
    28  	"time"
    29  	"unicode"
    30  	"unsafe"
    31  
    32  	"github.com/SmartMeshFoundation/Spectrum/common"
    33  	"github.com/SmartMeshFoundation/Spectrum/common/hexutil"
    34  	"github.com/SmartMeshFoundation/Spectrum/core/vm"
    35  	"github.com/SmartMeshFoundation/Spectrum/crypto"
    36  	"github.com/SmartMeshFoundation/Spectrum/log"
    37  	duktape "gopkg.in/olebedev/go-duktape.v3"
    38  )
    39  
    40  // bigIntegerJS is the minified version of https://github.com/peterolson/BigInteger.js.
    41  const bigIntegerJS = `var bigInt=function(undefined){"use strict";var BASE=1e7,LOG_BASE=7,MAX_INT=9007199254740992,MAX_INT_ARR=smallToArray(MAX_INT),LOG_MAX_INT=Math.log(MAX_INT);function Integer(v,radix){if(typeof v==="undefined")return Integer[0];if(typeof radix!=="undefined")return+radix===10?parseValue(v):parseBase(v,radix);return parseValue(v)}function BigInteger(value,sign){this.value=value;this.sign=sign;this.isSmall=false}BigInteger.prototype=Object.create(Integer.prototype);function SmallInteger(value){this.value=value;this.sign=value<0;this.isSmall=true}SmallInteger.prototype=Object.create(Integer.prototype);function isPrecise(n){return-MAX_INT<n&&n<MAX_INT}function smallToArray(n){if(n<1e7)return[n];if(n<1e14)return[n%1e7,Math.floor(n/1e7)];return[n%1e7,Math.floor(n/1e7)%1e7,Math.floor(n/1e14)]}function arrayToSmall(arr){trim(arr);var length=arr.length;if(length<4&&compareAbs(arr,MAX_INT_ARR)<0){switch(length){case 0:return 0;case 1:return arr[0];case 2:return arr[0]+arr[1]*BASE;default:return arr[0]+(arr[1]+arr[2]*BASE)*BASE}}return arr}function trim(v){var i=v.length;while(v[--i]===0);v.length=i+1}function createArray(length){var x=new Array(length);var i=-1;while(++i<length){x[i]=0}return x}function truncate(n){if(n>0)return Math.floor(n);return Math.ceil(n)}function add(a,b){var l_a=a.length,l_b=b.length,r=new Array(l_a),carry=0,base=BASE,sum,i;for(i=0;i<l_b;i++){sum=a[i]+b[i]+carry;carry=sum>=base?1:0;r[i]=sum-carry*base}while(i<l_a){sum=a[i]+carry;carry=sum===base?1:0;r[i++]=sum-carry*base}if(carry>0)r.push(carry);return r}function addAny(a,b){if(a.length>=b.length)return add(a,b);return add(b,a)}function addSmall(a,carry){var l=a.length,r=new Array(l),base=BASE,sum,i;for(i=0;i<l;i++){sum=a[i]-base+carry;carry=Math.floor(sum/base);r[i]=sum-carry*base;carry+=1}while(carry>0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}BigInteger.prototype.add=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.subtract(n.negate())}var a=this.value,b=n.value;if(n.isSmall){return new BigInteger(addSmall(a,Math.abs(b)),this.sign)}return new BigInteger(addAny(a,b),this.sign)};BigInteger.prototype.plus=BigInteger.prototype.add;SmallInteger.prototype.add=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.subtract(n.negate())}var b=n.value;if(n.isSmall){if(isPrecise(a+b))return new SmallInteger(a+b);b=smallToArray(Math.abs(b))}return new BigInteger(addSmall(b,Math.abs(a)),a<0)};SmallInteger.prototype.plus=SmallInteger.prototype.add;function subtract(a,b){var a_l=a.length,b_l=b.length,r=new Array(a_l),borrow=0,base=BASE,i,difference;for(i=0;i<b_l;i++){difference=a[i]-borrow-b[i];if(difference<0){difference+=base;borrow=1}else borrow=0;r[i]=difference}for(i=b_l;i<a_l;i++){difference=a[i]-borrow;if(difference<0)difference+=base;else{r[i++]=difference;break}r[i]=difference}for(;i<a_l;i++){r[i]=a[i]}trim(r);return r}function subtractAny(a,b,sign){var value;if(compareAbs(a,b)>=0){value=subtract(a,b)}else{value=subtract(b,a);sign=!sign}value=arrayToSmall(value);if(typeof value==="number"){if(sign)value=-value;return new SmallInteger(value)}return new BigInteger(value,sign)}function subtractSmall(a,b,sign){var l=a.length,r=new Array(l),carry=-b,base=BASE,i,difference;for(i=0;i<l;i++){difference=a[i]+carry;carry=Math.floor(difference/base);difference%=base;r[i]=difference<0?difference+base:difference}r=arrayToSmall(r);if(typeof r==="number"){if(sign)r=-r;return new SmallInteger(r)}return new BigInteger(r,sign)}BigInteger.prototype.subtract=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.add(n.negate())}var a=this.value,b=n.value;if(n.isSmall)return subtractSmall(a,Math.abs(b),this.sign);return subtractAny(a,b,this.sign)};BigInteger.prototype.minus=BigInteger.prototype.subtract;SmallInteger.prototype.subtract=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.add(n.negate())}var b=n.value;if(n.isSmall){return new SmallInteger(a-b)}return subtractSmall(b,Math.abs(a),a>=0)};SmallInteger.prototype.minus=SmallInteger.prototype.subtract;BigInteger.prototype.negate=function(){return new BigInteger(this.value,!this.sign)};SmallInteger.prototype.negate=function(){var sign=this.sign;var small=new SmallInteger(-this.value);small.sign=!sign;return small};BigInteger.prototype.abs=function(){return new BigInteger(this.value,false)};SmallInteger.prototype.abs=function(){return new SmallInteger(Math.abs(this.value))};function multiplyLong(a,b){var a_l=a.length,b_l=b.length,l=a_l+b_l,r=createArray(l),base=BASE,product,carry,i,a_i,b_j;for(i=0;i<a_l;++i){a_i=a[i];for(var j=0;j<b_l;++j){b_j=b[j];product=a_i*b_j+r[i+j];carry=Math.floor(product/base);r[i+j]=product-carry*base;r[i+j+1]+=carry}}trim(r);return r}function multiplySmall(a,b){var l=a.length,r=new Array(l),base=BASE,carry=0,product,i;for(i=0;i<l;i++){product=a[i]*b+carry;carry=Math.floor(product/base);r[i]=product-carry*base}while(carry>0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}function shiftLeft(x,n){var r=[];while(n-- >0)r.push(0);return r.concat(x)}function multiplyKaratsuba(x,y){var n=Math.max(x.length,y.length);if(n<=30)return multiplyLong(x,y);n=Math.ceil(n/2);var b=x.slice(n),a=x.slice(0,n),d=y.slice(n),c=y.slice(0,n);var ac=multiplyKaratsuba(a,c),bd=multiplyKaratsuba(b,d),abcd=multiplyKaratsuba(addAny(a,b),addAny(c,d));var product=addAny(addAny(ac,shiftLeft(subtract(subtract(abcd,ac),bd),n)),shiftLeft(bd,2*n));trim(product);return product}function useKaratsuba(l1,l2){return-.012*l1-.012*l2+15e-6*l1*l2>0}BigInteger.prototype.multiply=function(v){var n=parseValue(v),a=this.value,b=n.value,sign=this.sign!==n.sign,abs;if(n.isSmall){if(b===0)return Integer[0];if(b===1)return this;if(b===-1)return this.negate();abs=Math.abs(b);if(abs<BASE){return new BigInteger(multiplySmall(a,abs),sign)}b=smallToArray(abs)}if(useKaratsuba(a.length,b.length))return new BigInteger(multiplyKaratsuba(a,b),sign);return new BigInteger(multiplyLong(a,b),sign)};BigInteger.prototype.times=BigInteger.prototype.multiply;function multiplySmallAndArray(a,b,sign){if(a<BASE){return new BigInteger(multiplySmall(b,a),sign)}return new BigInteger(multiplyLong(b,smallToArray(a)),sign)}SmallInteger.prototype._multiplyBySmall=function(a){if(isPrecise(a.value*this.value)){return new SmallInteger(a.value*this.value)}return multiplySmallAndArray(Math.abs(a.value),smallToArray(Math.abs(this.value)),this.sign!==a.sign)};BigInteger.prototype._multiplyBySmall=function(a){if(a.value===0)return Integer[0];if(a.value===1)return this;if(a.value===-1)return this.negate();return multiplySmallAndArray(Math.abs(a.value),this.value,this.sign!==a.sign)};SmallInteger.prototype.multiply=function(v){return parseValue(v)._multiplyBySmall(this)};SmallInteger.prototype.times=SmallInteger.prototype.multiply;function square(a){var l=a.length,r=createArray(l+l),base=BASE,product,carry,i,a_i,a_j;for(i=0;i<l;i++){a_i=a[i];for(var j=0;j<l;j++){a_j=a[j];product=a_i*a_j+r[i+j];carry=Math.floor(product/base);r[i+j]=product-carry*base;r[i+j+1]+=carry}}trim(r);return r}BigInteger.prototype.square=function(){return new BigInteger(square(this.value),false)};SmallInteger.prototype.square=function(){var value=this.value*this.value;if(isPrecise(value))return new SmallInteger(value);return new BigInteger(square(smallToArray(Math.abs(this.value))),false)};function divMod1(a,b){var a_l=a.length,b_l=b.length,base=BASE,result=createArray(b.length),divisorMostSignificantDigit=b[b_l-1],lambda=Math.ceil(base/(2*divisorMostSignificantDigit)),remainder=multiplySmall(a,lambda),divisor=multiplySmall(b,lambda),quotientDigit,shift,carry,borrow,i,l,q;if(remainder.length<=a_l)remainder.push(0);divisor.push(0);divisorMostSignificantDigit=divisor[b_l-1];for(shift=a_l-b_l;shift>=0;shift--){quotientDigit=base-1;if(remainder[shift+b_l]!==divisorMostSignificantDigit){quotientDigit=Math.floor((remainder[shift+b_l]*base+remainder[shift+b_l-1])/divisorMostSignificantDigit)}carry=0;borrow=0;l=divisor.length;for(i=0;i<l;i++){carry+=quotientDigit*divisor[i];q=Math.floor(carry/base);borrow+=remainder[shift+i]-(carry-q*base);carry=q;if(borrow<0){remainder[shift+i]=borrow+base;borrow=-1}else{remainder[shift+i]=borrow;borrow=0}}while(borrow!==0){quotientDigit-=1;carry=0;for(i=0;i<l;i++){carry+=remainder[shift+i]-base+divisor[i];if(carry<0){remainder[shift+i]=carry+base;carry=0}else{remainder[shift+i]=carry;carry=1}}borrow+=carry}result[shift]=quotientDigit}remainder=divModSmall(remainder,lambda)[0];return[arrayToSmall(result),arrayToSmall(remainder)]}function divMod2(a,b){var a_l=a.length,b_l=b.length,result=[],part=[],base=BASE,guess,xlen,highx,highy,check;while(a_l){part.unshift(a[--a_l]);trim(part);if(compareAbs(part,b)<0){result.push(0);continue}xlen=part.length;highx=part[xlen-1]*base+part[xlen-2];highy=b[b_l-1]*base+b[b_l-2];if(xlen>b_l){highx=(highx+1)*base}guess=Math.ceil(highx/highy);do{check=multiplySmall(b,guess);if(compareAbs(check,part)<=0)break;guess--}while(guess);result.push(guess);part=subtract(part,check)}result.reverse();return[arrayToSmall(result),arrayToSmall(part)]}function divModSmall(value,lambda){var length=value.length,quotient=createArray(length),base=BASE,i,q,remainder,divisor;remainder=0;for(i=length-1;i>=0;--i){divisor=remainder*base+value[i];q=truncate(divisor/lambda);remainder=divisor-q*lambda;quotient[i]=q|0}return[quotient,remainder|0]}function divModAny(self,v){var value,n=parseValue(v);var a=self.value,b=n.value;var quotient;if(b===0)throw new Error("Cannot divide by zero");if(self.isSmall){if(n.isSmall){return[new SmallInteger(truncate(a/b)),new SmallInteger(a%b)]}return[Integer[0],self]}if(n.isSmall){if(b===1)return[self,Integer[0]];if(b==-1)return[self.negate(),Integer[0]];var abs=Math.abs(b);if(abs<BASE){value=divModSmall(a,abs);quotient=arrayToSmall(value[0]);var remainder=value[1];if(self.sign)remainder=-remainder;if(typeof quotient==="number"){if(self.sign!==n.sign)quotient=-quotient;return[new SmallInteger(quotient),new SmallInteger(remainder)]}return[new BigInteger(quotient,self.sign!==n.sign),new SmallInteger(remainder)]}b=smallToArray(abs)}var comparison=compareAbs(a,b);if(comparison===-1)return[Integer[0],self];if(comparison===0)return[Integer[self.sign===n.sign?1:-1],Integer[0]];if(a.length+b.length<=200)value=divMod1(a,b);else value=divMod2(a,b);quotient=value[0];var qSign=self.sign!==n.sign,mod=value[1],mSign=self.sign;if(typeof quotient==="number"){if(qSign)quotient=-quotient;quotient=new SmallInteger(quotient)}else quotient=new BigInteger(quotient,qSign);if(typeof mod==="number"){if(mSign)mod=-mod;mod=new SmallInteger(mod)}else mod=new BigInteger(mod,mSign);return[quotient,mod]}BigInteger.prototype.divmod=function(v){var result=divModAny(this,v);return{quotient:result[0],remainder:result[1]}};SmallInteger.prototype.divmod=BigInteger.prototype.divmod;BigInteger.prototype.divide=function(v){return divModAny(this,v)[0]};SmallInteger.prototype.over=SmallInteger.prototype.divide=BigInteger.prototype.over=BigInteger.prototype.divide;BigInteger.prototype.mod=function(v){return divModAny(this,v)[1]};SmallInteger.prototype.remainder=SmallInteger.prototype.mod=BigInteger.prototype.remainder=BigInteger.prototype.mod;BigInteger.prototype.pow=function(v){var n=parseValue(v),a=this.value,b=n.value,value,x,y;if(b===0)return Integer[1];if(a===0)return Integer[0];if(a===1)return Integer[1];if(a===-1)return n.isEven()?Integer[1]:Integer[-1];if(n.sign){return Integer[0]}if(!n.isSmall)throw new Error("The exponent "+n.toString()+" is too large.");if(this.isSmall){if(isPrecise(value=Math.pow(a,b)))return new SmallInteger(truncate(value))}x=this;y=Integer[1];while(true){if(b&1===1){y=y.times(x);--b}if(b===0)break;b/=2;x=x.square()}return y};SmallInteger.prototype.pow=BigInteger.prototype.pow;BigInteger.prototype.modPow=function(exp,mod){exp=parseValue(exp);mod=parseValue(mod);if(mod.isZero())throw new Error("Cannot take modPow with modulus 0");var r=Integer[1],base=this.mod(mod);while(exp.isPositive()){if(base.isZero())return Integer[0];if(exp.isOdd())r=r.multiply(base).mod(mod);exp=exp.divide(2);base=base.square().mod(mod)}return r};SmallInteger.prototype.modPow=BigInteger.prototype.modPow;function compareAbs(a,b){if(a.length!==b.length){return a.length>b.length?1:-1}for(var i=a.length-1;i>=0;i--){if(a[i]!==b[i])return a[i]>b[i]?1:-1}return 0}BigInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall)return 1;return compareAbs(a,b)};SmallInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=Math.abs(this.value),b=n.value;if(n.isSmall){b=Math.abs(b);return a===b?0:a>b?1:-1}return-1};BigInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(this.sign!==n.sign){return n.sign?1:-1}if(n.isSmall){return this.sign?-1:1}return compareAbs(a,b)*(this.sign?-1:1)};BigInteger.prototype.compareTo=BigInteger.prototype.compare;SmallInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall){return a==b?0:a>b?1:-1}if(a<0!==n.sign){return a<0?-1:1}return a<0?1:-1};SmallInteger.prototype.compareTo=SmallInteger.prototype.compare;BigInteger.prototype.equals=function(v){return this.compare(v)===0};SmallInteger.prototype.eq=SmallInteger.prototype.equals=BigInteger.prototype.eq=BigInteger.prototype.equals;BigInteger.prototype.notEquals=function(v){return this.compare(v)!==0};SmallInteger.prototype.neq=SmallInteger.prototype.notEquals=BigInteger.prototype.neq=BigInteger.prototype.notEquals;BigInteger.prototype.greater=function(v){return this.compare(v)>0};SmallInteger.prototype.gt=SmallInteger.prototype.greater=BigInteger.prototype.gt=BigInteger.prototype.greater;BigInteger.prototype.lesser=function(v){return this.compare(v)<0};SmallInteger.prototype.lt=SmallInteger.prototype.lesser=BigInteger.prototype.lt=BigInteger.prototype.lesser;BigInteger.prototype.greaterOrEquals=function(v){return this.compare(v)>=0};SmallInteger.prototype.geq=SmallInteger.prototype.greaterOrEquals=BigInteger.prototype.geq=BigInteger.prototype.greaterOrEquals;BigInteger.prototype.lesserOrEquals=function(v){return this.compare(v)<=0};SmallInteger.prototype.leq=SmallInteger.prototype.lesserOrEquals=BigInteger.prototype.leq=BigInteger.prototype.lesserOrEquals;BigInteger.prototype.isEven=function(){return(this.value[0]&1)===0};SmallInteger.prototype.isEven=function(){return(this.value&1)===0};BigInteger.prototype.isOdd=function(){return(this.value[0]&1)===1};SmallInteger.prototype.isOdd=function(){return(this.value&1)===1};BigInteger.prototype.isPositive=function(){return!this.sign};SmallInteger.prototype.isPositive=function(){return this.value>0};BigInteger.prototype.isNegative=function(){return this.sign};SmallInteger.prototype.isNegative=function(){return this.value<0};BigInteger.prototype.isUnit=function(){return false};SmallInteger.prototype.isUnit=function(){return Math.abs(this.value)===1};BigInteger.prototype.isZero=function(){return false};SmallInteger.prototype.isZero=function(){return this.value===0};BigInteger.prototype.isDivisibleBy=function(v){var n=parseValue(v);var value=n.value;if(value===0)return false;if(value===1)return true;if(value===2)return this.isEven();return this.mod(n).equals(Integer[0])};SmallInteger.prototype.isDivisibleBy=BigInteger.prototype.isDivisibleBy;function isBasicPrime(v){var n=v.abs();if(n.isUnit())return false;if(n.equals(2)||n.equals(3)||n.equals(5))return true;if(n.isEven()||n.isDivisibleBy(3)||n.isDivisibleBy(5))return false;if(n.lesser(25))return true}BigInteger.prototype.isPrime=function(){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs(),nPrev=n.prev();var a=[2,3,5,7,11,13,17,19],b=nPrev,d,t,i,x;while(b.isEven())b=b.divide(2);for(i=0;i<a.length;i++){x=bigInt(a[i]).modPow(b,n);if(x.equals(Integer[1])||x.equals(nPrev))continue;for(t=true,d=b;t&&d.lesser(nPrev);d=d.multiply(2)){x=x.square().mod(n);if(x.equals(nPrev))t=false}if(t)return false}return true};SmallInteger.prototype.isPrime=BigInteger.prototype.isPrime;BigInteger.prototype.isProbablePrime=function(iterations){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs();var t=iterations===undefined?5:iterations;for(var i=0;i<t;i++){var a=bigInt.randBetween(2,n.minus(2));if(!a.modPow(n.prev(),n).isUnit())return false}return true};SmallInteger.prototype.isProbablePrime=BigInteger.prototype.isProbablePrime;BigInteger.prototype.modInv=function(n){var t=bigInt.zero,newT=bigInt.one,r=parseValue(n),newR=this.abs(),q,lastT,lastR;while(!newR.equals(bigInt.zero)){q=r.divide(newR);lastT=t;lastR=r;t=newT;r=newR;newT=lastT.subtract(q.multiply(newT));newR=lastR.subtract(q.multiply(newR))}if(!r.equals(1))throw new Error(this.toString()+" and "+n.toString()+" are not co-prime");if(t.compare(0)===-1){t=t.add(n)}if(this.isNegative()){return t.negate()}return t};SmallInteger.prototype.modInv=BigInteger.prototype.modInv;BigInteger.prototype.next=function(){var value=this.value;if(this.sign){return subtractSmall(value,1,this.sign)}return new BigInteger(addSmall(value,1),this.sign)};SmallInteger.prototype.next=function(){var value=this.value;if(value+1<MAX_INT)return new SmallInteger(value+1);return new BigInteger(MAX_INT_ARR,false)};BigInteger.prototype.prev=function(){var value=this.value;if(this.sign){return new BigInteger(addSmall(value,1),true)}return subtractSmall(value,1,this.sign)};SmallInteger.prototype.prev=function(){var value=this.value;if(value-1>-MAX_INT)return new SmallInteger(value-1);return new BigInteger(MAX_INT_ARR,true)};var powersOfTwo=[1];while(2*powersOfTwo[powersOfTwo.length-1]<=BASE)powersOfTwo.push(2*powersOfTwo[powersOfTwo.length-1]);var powers2Length=powersOfTwo.length,highestPower2=powersOfTwo[powers2Length-1];function shift_isSmall(n){return(typeof n==="number"||typeof n==="string")&&+Math.abs(n)<=BASE||n instanceof BigInteger&&n.value.length<=1}BigInteger.prototype.shiftLeft=function(n){if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftRight(-n);var result=this;while(n>=powers2Length){result=result.multiply(highestPower2);n-=powers2Length-1}return result.multiply(powersOfTwo[n])};SmallInteger.prototype.shiftLeft=BigInteger.prototype.shiftLeft;BigInteger.prototype.shiftRight=function(n){var remQuo;if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftLeft(-n);var result=this;while(n>=powers2Length){if(result.isZero())return result;remQuo=divModAny(result,highestPower2);result=remQuo[1].isNegative()?remQuo[0].prev():remQuo[0];n-=powers2Length-1}remQuo=divModAny(result,powersOfTwo[n]);return remQuo[1].isNegative()?remQuo[0].prev():remQuo[0]};SmallInteger.prototype.shiftRight=BigInteger.prototype.shiftRight;function bitwise(x,y,fn){y=parseValue(y);var xSign=x.isNegative(),ySign=y.isNegative();var xRem=xSign?x.not():x,yRem=ySign?y.not():y;var xDigit=0,yDigit=0;var xDivMod=null,yDivMod=null;var result=[];while(!xRem.isZero()||!yRem.isZero()){xDivMod=divModAny(xRem,highestPower2);xDigit=xDivMod[1].toJSNumber();if(xSign){xDigit=highestPower2-1-xDigit}yDivMod=divModAny(yRem,highestPower2);yDigit=yDivMod[1].toJSNumber();if(ySign){yDigit=highestPower2-1-yDigit}xRem=xDivMod[0];yRem=yDivMod[0];result.push(fn(xDigit,yDigit))}var sum=fn(xSign?1:0,ySign?1:0)!==0?bigInt(-1):bigInt(0);for(var i=result.length-1;i>=0;i-=1){sum=sum.multiply(highestPower2).add(bigInt(result[i]))}return sum}BigInteger.prototype.not=function(){return this.negate().prev()};SmallInteger.prototype.not=BigInteger.prototype.not;BigInteger.prototype.and=function(n){return bitwise(this,n,function(a,b){return a&b})};SmallInteger.prototype.and=BigInteger.prototype.and;BigInteger.prototype.or=function(n){return bitwise(this,n,function(a,b){return a|b})};SmallInteger.prototype.or=BigInteger.prototype.or;BigInteger.prototype.xor=function(n){return bitwise(this,n,function(a,b){return a^b})};SmallInteger.prototype.xor=BigInteger.prototype.xor;var LOBMASK_I=1<<30,LOBMASK_BI=(BASE&-BASE)*(BASE&-BASE)|LOBMASK_I;function roughLOB(n){var v=n.value,x=typeof v==="number"?v|LOBMASK_I:v[0]+v[1]*BASE|LOBMASK_BI;return x&-x}function max(a,b){a=parseValue(a);b=parseValue(b);return a.greater(b)?a:b}function min(a,b){a=parseValue(a);b=parseValue(b);return a.lesser(b)?a:b}function gcd(a,b){a=parseValue(a).abs();b=parseValue(b).abs();if(a.equals(b))return a;if(a.isZero())return b;if(b.isZero())return a;var c=Integer[1],d,t;while(a.isEven()&&b.isEven()){d=Math.min(roughLOB(a),roughLOB(b));a=a.divide(d);b=b.divide(d);c=c.multiply(d)}while(a.isEven()){a=a.divide(roughLOB(a))}do{while(b.isEven()){b=b.divide(roughLOB(b))}if(a.greater(b)){t=b;b=a;a=t}b=b.subtract(a)}while(!b.isZero());return c.isUnit()?a:a.multiply(c)}function lcm(a,b){a=parseValue(a).abs();b=parseValue(b).abs();return a.divide(gcd(a,b)).multiply(b)}function randBetween(a,b){a=parseValue(a);b=parseValue(b);var low=min(a,b),high=max(a,b);var range=high.subtract(low).add(1);if(range.isSmall)return low.add(Math.floor(Math.random()*range));var length=range.value.length-1;var result=[],restricted=true;for(var i=length;i>=0;i--){var top=restricted?range.value[i]:BASE;var digit=truncate(Math.random()*top);result.unshift(digit);if(digit<top)restricted=false}result=arrayToSmall(result);return low.add(typeof result==="number"?new SmallInteger(result):new BigInteger(result,false))}var parseBase=function(text,base){var length=text.length;var i;var absBase=Math.abs(base);for(var i=0;i<length;i++){var c=text[i].toLowerCase();if(c==="-")continue;if(/[a-z0-9]/.test(c)){if(/[0-9]/.test(c)&&+c>=absBase){if(c==="1"&&absBase===1)continue;throw new Error(c+" is not a valid digit in base "+base+".")}else if(c.charCodeAt(0)-87>=absBase){throw new Error(c+" is not a valid digit in base "+base+".")}}}if(2<=base&&base<=36){if(length<=LOG_MAX_INT/Math.log(base)){var result=parseInt(text,base);if(isNaN(result)){throw new Error(c+" is not a valid digit in base "+base+".")}return new SmallInteger(parseInt(text,base))}}base=parseValue(base);var digits=[];var isNegative=text[0]==="-";for(i=isNegative?1:0;i<text.length;i++){var c=text[i].toLowerCase(),charCode=c.charCodeAt(0);if(48<=charCode&&charCode<=57)digits.push(parseValue(c));else if(97<=charCode&&charCode<=122)digits.push(parseValue(c.charCodeAt(0)-87));else if(c==="<"){var start=i;do{i++}while(text[i]!==">");digits.push(parseValue(text.slice(start+1,i)))}else throw new Error(c+" is not a valid character")}return parseBaseFromArray(digits,base,isNegative)};function parseBaseFromArray(digits,base,isNegative){var val=Integer[0],pow=Integer[1],i;for(i=digits.length-1;i>=0;i--){val=val.add(digits[i].times(pow));pow=pow.times(base)}return isNegative?val.negate():val}function stringify(digit){var v=digit.value;if(typeof v==="number")v=[v];if(v.length===1&&v[0]<=35){return"0123456789abcdefghijklmnopqrstuvwxyz".charAt(v[0])}return"<"+v+">"}function toBase(n,base){base=bigInt(base);if(base.isZero()){if(n.isZero())return"0";throw new Error("Cannot convert nonzero numbers to base 0.")}if(base.equals(-1)){if(n.isZero())return"0";if(n.isNegative())return new Array(1-n).join("10");return"1"+new Array(+n).join("01")}var minusSign="";if(n.isNegative()&&base.isPositive()){minusSign="-";n=n.abs()}if(base.equals(1)){if(n.isZero())return"0";return minusSign+new Array(+n+1).join(1)}var out=[];var left=n,divmod;while(left.isNegative()||left.compareAbs(base)>=0){divmod=left.divmod(base);left=divmod.quotient;var digit=divmod.remainder;if(digit.isNegative()){digit=base.minus(digit).abs();left=left.next()}out.push(stringify(digit))}out.push(stringify(left));return minusSign+out.reverse().join("")}BigInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!==10)return toBase(this,radix);var v=this.value,l=v.length,str=String(v[--l]),zeros="0000000",digit;while(--l>=0){digit=String(v[l]);str+=zeros.slice(digit.length)+digit}var sign=this.sign?"-":"";return sign+str};SmallInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!=10)return toBase(this,radix);return String(this.value)};BigInteger.prototype.toJSON=SmallInteger.prototype.toJSON=function(){return this.toString()};BigInteger.prototype.valueOf=function(){return+this.toString()};BigInteger.prototype.toJSNumber=BigInteger.prototype.valueOf;SmallInteger.prototype.valueOf=function(){return this.value};SmallInteger.prototype.toJSNumber=SmallInteger.prototype.valueOf;function parseStringValue(v){if(isPrecise(+v)){var x=+v;if(x===truncate(x))return new SmallInteger(x);throw"Invalid integer: "+v}var sign=v[0]==="-";if(sign)v=v.slice(1);var split=v.split(/e/i);if(split.length>2)throw new Error("Invalid integer: "+split.join("e"));if(split.length===2){var exp=split[1];if(exp[0]==="+")exp=exp.slice(1);exp=+exp;if(exp!==truncate(exp)||!isPrecise(exp))throw new Error("Invalid integer: "+exp+" is not a valid exponent.");var text=split[0];var decimalPlace=text.indexOf(".");if(decimalPlace>=0){exp-=text.length-decimalPlace-1;text=text.slice(0,decimalPlace)+text.slice(decimalPlace+1)}if(exp<0)throw new Error("Cannot include negative exponent part for integers");text+=new Array(exp+1).join("0");v=text}var isValid=/^([0-9][0-9]*)$/.test(v);if(!isValid)throw new Error("Invalid integer: "+v);var r=[],max=v.length,l=LOG_BASE,min=max-l;while(max>0){r.push(+v.slice(min,max));min-=l;if(min<0)min=0;max-=l}trim(r);return new BigInteger(r,sign)}function parseNumberValue(v){if(isPrecise(v)){if(v!==truncate(v))throw new Error(v+" is not an integer.");return new SmallInteger(v)}return parseStringValue(v.toString())}function parseValue(v){if(typeof v==="number"){return parseNumberValue(v)}if(typeof v==="string"){return parseStringValue(v)}return v}for(var i=0;i<1e3;i++){Integer[i]=new SmallInteger(i);if(i>0)Integer[-i]=new SmallInteger(-i)}Integer.one=Integer[1];Integer.zero=Integer[0];Integer.minusOne=Integer[-1];Integer.max=max;Integer.min=min;Integer.gcd=gcd;Integer.lcm=lcm;Integer.isInstance=function(x){return x instanceof BigInteger||x instanceof SmallInteger};Integer.randBetween=randBetween;Integer.fromArray=function(digits,base,isNegative){return parseBaseFromArray(digits.map(parseValue),parseValue(base||10),isNegative)};return Integer}();if(typeof module!=="undefined"&&module.hasOwnProperty("exports")){module.exports=bigInt}if(typeof define==="function"&&define.amd){define("big-integer",[],function(){return bigInt})}; bigInt`
    42  
    43  func camel(str string) string {
    44  	pieces := strings.Split(str, "_")
    45  	for i := 1; i < len(pieces); i++ {
    46  		pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:]
    47  	}
    48  	return strings.Join(pieces, "")
    49  }
    50  
    51  var assetTracers = make(map[string]string)
    52  
    53  // init retrieves the JavaScript transaction tracers included in go-ethereum.
    54  func init() {
    55  	for _, file := range tracers.AssetNames() {
    56  		name := camel(strings.TrimSuffix(file, ".js"))
    57  		assetTracers[name] = string(tracers.MustAsset(file))
    58  	}
    59  	RegisterLookup(true, newJsTracer)
    60  }
    61  
    62  // makeSlice convert an unsafe memory pointer with the given type into a Go byte
    63  // slice.
    64  //
    65  // Note, the returned slice uses the same memory area as the input arguments.
    66  // If those are duktape stack items, popping them off **will** make the slice
    67  // contents change.
    68  func makeSlice(ptr unsafe.Pointer, size uint) []byte {
    69  	var sl = struct {
    70  		addr uintptr
    71  		len  int
    72  		cap  int
    73  	}{uintptr(ptr), int(size), int(size)}
    74  
    75  	return *(*[]byte)(unsafe.Pointer(&sl))
    76  }
    77  
    78  // popSlice pops a buffer off the JavaScript stack and returns it as a slice.
    79  func popSlice(ctx *duktape.Context) []byte {
    80  	blob := common.CopyBytes(makeSlice(ctx.GetBuffer(-1)))
    81  	ctx.Pop()
    82  	return blob
    83  }
    84  
    85  // pushBigInt create a JavaScript BigInteger in the VM.
    86  func pushBigInt(n *big.Int, ctx *duktape.Context) {
    87  	ctx.GetGlobalString("bigInt")
    88  	ctx.PushString(n.String())
    89  	ctx.Call(1)
    90  }
    91  
    92  // opWrapper provides a JavaScript wrapper around OpCode.
    93  type opWrapper struct {
    94  	op vm.OpCode
    95  }
    96  
    97  // pushObject assembles a JSVM object wrapping a swappable opcode and pushes it
    98  // onto the VM stack.
    99  func (ow *opWrapper) pushObject(vm *duktape.Context) {
   100  	obj := vm.PushObject()
   101  
   102  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(int(ow.op)); return 1 })
   103  	vm.PutPropString(obj, "toNumber")
   104  
   105  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushString(ow.op.String()); return 1 })
   106  	vm.PutPropString(obj, "toString")
   107  
   108  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushBoolean(ow.op.IsPush()); return 1 })
   109  	vm.PutPropString(obj, "isPush")
   110  }
   111  
   112  // memoryWrapper provides a JavaScript wrapper around vm.Memory.
   113  type memoryWrapper struct {
   114  	memory *vm.Memory
   115  }
   116  
   117  // slice returns the requested range of memory as a byte slice.
   118  func (mw *memoryWrapper) slice(begin, end int64) []byte {
   119  	if mw.memory.Len() < int(end) {
   120  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   121  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   122  		log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", begin, "size", end-begin)
   123  		return nil
   124  	}
   125  	return mw.memory.Get(begin, end-begin)
   126  }
   127  
   128  // getUint returns the 32 bytes at the specified address interpreted as a uint.
   129  func (mw *memoryWrapper) getUint(addr int64) *big.Int {
   130  	if mw.memory.Len() < int(addr)+32 {
   131  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   132  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   133  		log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", addr, "size", 32)
   134  		return new(big.Int)
   135  	}
   136  	return new(big.Int).SetBytes(mw.memory.GetPtr(addr, 32))
   137  }
   138  
   139  // pushObject assembles a JSVM object wrapping a swappable memory and pushes it
   140  // onto the VM stack.
   141  func (mw *memoryWrapper) pushObject(vm *duktape.Context) {
   142  	obj := vm.PushObject()
   143  
   144  	// Generate the `slice` method which takes two ints and returns a buffer
   145  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   146  		blob := mw.slice(int64(ctx.GetInt(-2)), int64(ctx.GetInt(-1)))
   147  		ctx.Pop2()
   148  
   149  		ptr := ctx.PushFixedBuffer(len(blob))
   150  		copy(makeSlice(ptr, uint(len(blob))), blob[:])
   151  		return 1
   152  	})
   153  	vm.PutPropString(obj, "slice")
   154  
   155  	// Generate the `getUint` method which takes an int and returns a bigint
   156  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   157  		offset := int64(ctx.GetInt(-1))
   158  		ctx.Pop()
   159  
   160  		pushBigInt(mw.getUint(offset), ctx)
   161  		return 1
   162  	})
   163  	vm.PutPropString(obj, "getUint")
   164  }
   165  
   166  // stackWrapper provides a JavaScript wrapper around vm.Stack.
   167  type stackWrapper struct {
   168  	stack *vm.Stack
   169  }
   170  
   171  // peek returns the nth-from-the-top element of the stack.
   172  func (sw *stackWrapper) peek(idx int) *big.Int {
   173  	if len(sw.stack.Data()) <= idx {
   174  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   175  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   176  		log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
   177  		return new(big.Int)
   178  	}
   179  	return sw.stack.Data()[len(sw.stack.Data())-idx-1].ToBig()
   180  }
   181  
   182  // pushObject assembles a JSVM object wrapping a swappable stack and pushes it
   183  // onto the VM stack.
   184  func (sw *stackWrapper) pushObject(vm *duktape.Context) {
   185  	obj := vm.PushObject()
   186  
   187  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(len(sw.stack.Data())); return 1 })
   188  	vm.PutPropString(obj, "length")
   189  
   190  	// Generate the `peek` method which takes an int and returns a bigint
   191  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   192  		offset := ctx.GetInt(-1)
   193  		ctx.Pop()
   194  
   195  		pushBigInt(sw.peek(offset), ctx)
   196  		return 1
   197  	})
   198  	vm.PutPropString(obj, "peek")
   199  }
   200  
   201  // dbWrapper provides a JavaScript wrapper around vm.Database.
   202  type dbWrapper struct {
   203  	db vm.StateDB
   204  }
   205  
   206  // pushObject assembles a JSVM object wrapping a swappable database and pushes it
   207  // onto the VM stack.
   208  func (dw *dbWrapper) pushObject(vm *duktape.Context) {
   209  	obj := vm.PushObject()
   210  
   211  	// Push the wrapper for statedb.GetBalance
   212  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   213  		pushBigInt(dw.db.GetBalance(common.BytesToAddress(popSlice(ctx))), ctx)
   214  		return 1
   215  	})
   216  	vm.PutPropString(obj, "getBalance")
   217  
   218  	// Push the wrapper for statedb.GetNonce
   219  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   220  		ctx.PushInt(int(dw.db.GetNonce(common.BytesToAddress(popSlice(ctx)))))
   221  		return 1
   222  	})
   223  	vm.PutPropString(obj, "getNonce")
   224  
   225  	// Push the wrapper for statedb.GetCode
   226  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   227  		code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx)))
   228  
   229  		ptr := ctx.PushFixedBuffer(len(code))
   230  		copy(makeSlice(ptr, uint(len(code))), code[:])
   231  		return 1
   232  	})
   233  	vm.PutPropString(obj, "getCode")
   234  
   235  	// Push the wrapper for statedb.GetState
   236  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   237  		hash := popSlice(ctx)
   238  		addr := popSlice(ctx)
   239  
   240  		state := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash))
   241  
   242  		ptr := ctx.PushFixedBuffer(len(state))
   243  		copy(makeSlice(ptr, uint(len(state))), state[:])
   244  		return 1
   245  	})
   246  	vm.PutPropString(obj, "getState")
   247  
   248  	// Push the wrapper for statedb.Exists
   249  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   250  		ctx.PushBoolean(dw.db.Exist(common.BytesToAddress(popSlice(ctx))))
   251  		return 1
   252  	})
   253  	vm.PutPropString(obj, "exists")
   254  }
   255  
   256  // contractWrapper provides a JavaScript wrapper around vm.Contract
   257  type contractWrapper struct {
   258  	contract *vm.Contract
   259  }
   260  
   261  // pushObject assembles a JSVM object wrapping a swappable contract and pushes it
   262  // onto the VM stack.
   263  func (cw *contractWrapper) pushObject(vm *duktape.Context) {
   264  	obj := vm.PushObject()
   265  
   266  	// Push the wrapper for contract.Caller
   267  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   268  		ptr := ctx.PushFixedBuffer(20)
   269  		copy(makeSlice(ptr, 20), cw.contract.Caller().Bytes())
   270  		return 1
   271  	})
   272  	vm.PutPropString(obj, "getCaller")
   273  
   274  	// Push the wrapper for contract.Address
   275  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   276  		ptr := ctx.PushFixedBuffer(20)
   277  		copy(makeSlice(ptr, 20), cw.contract.Address().Bytes())
   278  		return 1
   279  	})
   280  	vm.PutPropString(obj, "getAddress")
   281  
   282  	// Push the wrapper for contract.Value
   283  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   284  		pushBigInt(cw.contract.Value(), ctx)
   285  		return 1
   286  	})
   287  	vm.PutPropString(obj, "getValue")
   288  
   289  	// Push the wrapper for contract.Input
   290  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   291  		blob := cw.contract.Input
   292  
   293  		ptr := ctx.PushFixedBuffer(len(blob))
   294  		copy(makeSlice(ptr, uint(len(blob))), blob[:])
   295  		return 1
   296  	})
   297  	vm.PutPropString(obj, "getInput")
   298  }
   299  
   300  func pushValue(ctx *duktape.Context, val interface{}) {
   301  	switch val := val.(type) {
   302  	case uint64:
   303  		ctx.PushUint(uint(val))
   304  	case string:
   305  		ctx.PushString(val)
   306  	case []byte:
   307  		ptr := ctx.PushFixedBuffer(len(val))
   308  		copy(makeSlice(ptr, uint(len(val))), val)
   309  	case common.Address:
   310  		ptr := ctx.PushFixedBuffer(20)
   311  		copy(makeSlice(ptr, 20), val[:])
   312  	case *big.Int:
   313  		pushBigInt(val, ctx)
   314  	case int:
   315  		ctx.PushInt(val)
   316  	case uint:
   317  		ctx.PushUint(val)
   318  	case common.Hash:
   319  		ptr := ctx.PushFixedBuffer(32)
   320  		copy(makeSlice(ptr, 32), val[:])
   321  	default:
   322  		panic(fmt.Sprintf("unsupported type: %T", val))
   323  	}
   324  }
   325  
   326  type frame struct {
   327  	typ   *string
   328  	from  *common.Address
   329  	to    *common.Address
   330  	input []byte
   331  	gas   *uint
   332  	value *big.Int
   333  }
   334  
   335  func newFrame() *frame {
   336  	return &frame{
   337  		typ:  new(string),
   338  		from: new(common.Address),
   339  		to:   new(common.Address),
   340  		gas:  new(uint),
   341  	}
   342  }
   343  
   344  func (f *frame) pushObject(vm *duktape.Context) {
   345  	obj := vm.PushObject()
   346  
   347  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.typ); return 1 })
   348  	vm.PutPropString(obj, "getType")
   349  
   350  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.from); return 1 })
   351  	vm.PutPropString(obj, "getFrom")
   352  
   353  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.to); return 1 })
   354  	vm.PutPropString(obj, "getTo")
   355  
   356  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, f.input); return 1 })
   357  	vm.PutPropString(obj, "getInput")
   358  
   359  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.gas); return 1 })
   360  	vm.PutPropString(obj, "getGas")
   361  
   362  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   363  		if f.value != nil {
   364  			pushValue(ctx, f.value)
   365  		} else {
   366  			ctx.PushUndefined()
   367  		}
   368  		return 1
   369  	})
   370  	vm.PutPropString(obj, "getValue")
   371  }
   372  
   373  type frameResult struct {
   374  	gasUsed    *uint
   375  	output     []byte
   376  	errorValue *string
   377  }
   378  
   379  func newFrameResult() *frameResult {
   380  	return &frameResult{
   381  		gasUsed: new(uint),
   382  	}
   383  }
   384  
   385  func (r *frameResult) pushObject(vm *duktape.Context) {
   386  	obj := vm.PushObject()
   387  
   388  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *r.gasUsed); return 1 })
   389  	vm.PutPropString(obj, "getGasUsed")
   390  
   391  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, r.output); return 1 })
   392  	vm.PutPropString(obj, "getOutput")
   393  
   394  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   395  		if r.errorValue != nil {
   396  			pushValue(ctx, *r.errorValue)
   397  		} else {
   398  			ctx.PushUndefined()
   399  		}
   400  		return 1
   401  	})
   402  	vm.PutPropString(obj, "getError")
   403  }
   404  
   405  // Tracer provides an implementation of Tracer that evaluates a Javascript
   406  // function for each VM execution step.
   407  type jsTracer struct {
   408  	vm  *duktape.Context // Javascript VM instance
   409  	env *vm.EVM          // EVM instance executing the code being traced
   410  
   411  	tracerObject int // Stack index of the tracer JavaScript object
   412  	stateObject  int // Stack index of the global state to pull arguments from
   413  
   414  	opWrapper       *opWrapper       // Wrapper around the VM opcode
   415  	stackWrapper    *stackWrapper    // Wrapper around the VM stack
   416  	memoryWrapper   *memoryWrapper   // Wrapper around the VM memory
   417  	contractWrapper *contractWrapper // Wrapper around the contract object
   418  	dbWrapper       *dbWrapper       // Wrapper around the VM environment
   419  
   420  	pcValue     *uint   // Swappable pc value wrapped by a log accessor
   421  	gasValue    *uint   // Swappable gas value wrapped by a log accessor
   422  	costValue   *uint   // Swappable cost value wrapped by a log accessor
   423  	depthValue  *uint   // Swappable depth value wrapped by a log accessor
   424  	errorValue  *string // Swappable error value wrapped by a log accessor
   425  	refundValue *uint   // Swappable refund value wrapped by a log accessor
   426  
   427  	frame       *frame       // Represents entry into call frame. Fields are swappable
   428  	frameResult *frameResult // Represents exit from a call frame. Fields are swappable
   429  
   430  	ctx map[string]interface{} // Transaction context gathered throughout execution
   431  	err error                  // Error, if one has occurred
   432  
   433  	interrupt uint32 // Atomic flag to signal execution interruption
   434  	reason    error  // Textual reason for the interruption
   435  
   436  	activePrecompiles []common.Address // Updated on CaptureStart based on given rules
   437  	traceSteps        bool             // When true, will invoke step() on each opcode
   438  	traceCallFrames   bool             // When true, will invoke enter() and exit() js funcs
   439  }
   440  
   441  // New instantiates a new tracer instance. code specifies a Javascript snippet,
   442  // which must evaluate to an expression returning an object with 'step', 'fault'
   443  // and 'result' functions.
   444  func newJsTracer(code string, ctx *Context) (Tracer, error) {
   445  	if c, ok := assetTracers[code]; ok {
   446  		code = c
   447  	}
   448  	if ctx == nil {
   449  		ctx = new(Context)
   450  	}
   451  	tracer := &jsTracer{
   452  		vm:              duktape.New(),
   453  		ctx:             make(map[string]interface{}),
   454  		opWrapper:       new(opWrapper),
   455  		stackWrapper:    new(stackWrapper),
   456  		memoryWrapper:   new(memoryWrapper),
   457  		contractWrapper: new(contractWrapper),
   458  		dbWrapper:       new(dbWrapper),
   459  		pcValue:         new(uint),
   460  		gasValue:        new(uint),
   461  		costValue:       new(uint),
   462  		depthValue:      new(uint),
   463  		refundValue:     new(uint),
   464  		frame:           newFrame(),
   465  		frameResult:     newFrameResult(),
   466  	}
   467  	if ctx.BlockHash != (common.Hash{}) {
   468  		tracer.ctx["blockHash"] = ctx.BlockHash
   469  
   470  		if ctx.TxHash != (common.Hash{}) {
   471  			tracer.ctx["txIndex"] = ctx.TxIndex
   472  			tracer.ctx["txHash"] = ctx.TxHash
   473  		}
   474  	}
   475  	// Set up builtins for this environment
   476  	tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int {
   477  		ctx.PushString(hexutil.Encode(popSlice(ctx)))
   478  		return 1
   479  	})
   480  	tracer.vm.PushGlobalGoFunction("toWord", func(ctx *duktape.Context) int {
   481  		var word common.Hash
   482  		if ptr, size := ctx.GetBuffer(-1); ptr != nil {
   483  			word = common.BytesToHash(makeSlice(ptr, size))
   484  		} else {
   485  			word = common.HexToHash(ctx.GetString(-1))
   486  		}
   487  		ctx.Pop()
   488  		copy(makeSlice(ctx.PushFixedBuffer(32), 32), word[:])
   489  		return 1
   490  	})
   491  	tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *duktape.Context) int {
   492  		var addr common.Address
   493  		if ptr, size := ctx.GetBuffer(-1); ptr != nil {
   494  			addr = common.BytesToAddress(makeSlice(ptr, size))
   495  		} else {
   496  			addr = common.HexToAddress(ctx.GetString(-1))
   497  		}
   498  		ctx.Pop()
   499  		copy(makeSlice(ctx.PushFixedBuffer(20), 20), addr[:])
   500  		return 1
   501  	})
   502  	tracer.vm.PushGlobalGoFunction("toContract", func(ctx *duktape.Context) int {
   503  		var from common.Address
   504  		if ptr, size := ctx.GetBuffer(-2); ptr != nil {
   505  			from = common.BytesToAddress(makeSlice(ptr, size))
   506  		} else {
   507  			from = common.HexToAddress(ctx.GetString(-2))
   508  		}
   509  		nonce := uint64(ctx.GetInt(-1))
   510  		ctx.Pop2()
   511  
   512  		contract := crypto.CreateAddress(from, nonce)
   513  		copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
   514  		return 1
   515  	})
   516  	tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int {
   517  		var from common.Address
   518  		if ptr, size := ctx.GetBuffer(-3); ptr != nil {
   519  			from = common.BytesToAddress(makeSlice(ptr, size))
   520  		} else {
   521  			from = common.HexToAddress(ctx.GetString(-3))
   522  		}
   523  		// Retrieve salt hex string from js stack
   524  		salt := common.HexToHash(ctx.GetString(-2))
   525  		// Retrieve code slice from js stack
   526  		var code []byte
   527  		if ptr, size := ctx.GetBuffer(-1); ptr != nil {
   528  			code = common.CopyBytes(makeSlice(ptr, size))
   529  		} else {
   530  			code = common.FromHex(ctx.GetString(-1))
   531  		}
   532  		codeHash := crypto.Keccak256(code)
   533  		ctx.Pop3()
   534  		contract := crypto.CreateAddress2(from, salt, codeHash)
   535  		copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
   536  		return 1
   537  	})
   538  	tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
   539  		addr := common.BytesToAddress(popSlice(ctx))
   540  		for _, p := range tracer.activePrecompiles {
   541  			if p == addr {
   542  				ctx.PushBoolean(true)
   543  				return 1
   544  			}
   545  		}
   546  		ctx.PushBoolean(false)
   547  		return 1
   548  	})
   549  	tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int {
   550  		start, end := ctx.GetInt(-2), ctx.GetInt(-1)
   551  		ctx.Pop2()
   552  
   553  		blob := popSlice(ctx)
   554  		size := end - start
   555  
   556  		if start < 0 || start > end || end > len(blob) {
   557  			// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   558  			// runtime goes belly up https://github.com/golang/go/issues/15639.
   559  			log.Warn("Tracer accessed out of bound memory", "available", len(blob), "offset", start, "size", size)
   560  			ctx.PushFixedBuffer(0)
   561  			return 1
   562  		}
   563  		copy(makeSlice(ctx.PushFixedBuffer(size), uint(size)), blob[start:end])
   564  		return 1
   565  	})
   566  	// Push the JavaScript tracer as object #0 onto the JSVM stack and validate it
   567  	if err := tracer.vm.PevalString("(" + code + ")"); err != nil {
   568  		log.Warn("Failed to compile tracer", "err", err)
   569  		return nil, err
   570  	}
   571  	tracer.tracerObject = 0 // yeah, nice, eval can't return the index itself
   572  
   573  	hasStep := tracer.vm.GetPropString(tracer.tracerObject, "step")
   574  	tracer.vm.Pop()
   575  
   576  	if !tracer.vm.GetPropString(tracer.tracerObject, "fault") {
   577  		return nil, fmt.Errorf("trace object must expose a function fault()")
   578  	}
   579  	tracer.vm.Pop()
   580  
   581  	if !tracer.vm.GetPropString(tracer.tracerObject, "result") {
   582  		return nil, fmt.Errorf("trace object must expose a function result()")
   583  	}
   584  	tracer.vm.Pop()
   585  
   586  	hasEnter := tracer.vm.GetPropString(tracer.tracerObject, "enter")
   587  	tracer.vm.Pop()
   588  	hasExit := tracer.vm.GetPropString(tracer.tracerObject, "exit")
   589  	tracer.vm.Pop()
   590  	if hasEnter != hasExit {
   591  		return nil, fmt.Errorf("trace object must expose either both or none of enter() and exit()")
   592  	}
   593  	tracer.traceCallFrames = hasEnter && hasExit
   594  	tracer.traceSteps = hasStep
   595  
   596  	// Tracer is valid, inject the big int library to access large numbers
   597  	tracer.vm.EvalString(bigIntegerJS)
   598  	tracer.vm.PutGlobalString("bigInt")
   599  
   600  	// Push the global environment state as object #1 into the JSVM stack
   601  	tracer.stateObject = tracer.vm.PushObject()
   602  
   603  	logObject := tracer.vm.PushObject()
   604  
   605  	tracer.opWrapper.pushObject(tracer.vm)
   606  	tracer.vm.PutPropString(logObject, "op")
   607  
   608  	tracer.stackWrapper.pushObject(tracer.vm)
   609  	tracer.vm.PutPropString(logObject, "stack")
   610  
   611  	tracer.memoryWrapper.pushObject(tracer.vm)
   612  	tracer.vm.PutPropString(logObject, "memory")
   613  
   614  	tracer.contractWrapper.pushObject(tracer.vm)
   615  	tracer.vm.PutPropString(logObject, "contract")
   616  
   617  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.pcValue); return 1 })
   618  	tracer.vm.PutPropString(logObject, "getPC")
   619  
   620  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.gasValue); return 1 })
   621  	tracer.vm.PutPropString(logObject, "getGas")
   622  
   623  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.costValue); return 1 })
   624  	tracer.vm.PutPropString(logObject, "getCost")
   625  
   626  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.depthValue); return 1 })
   627  	tracer.vm.PutPropString(logObject, "getDepth")
   628  
   629  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.refundValue); return 1 })
   630  	tracer.vm.PutPropString(logObject, "getRefund")
   631  
   632  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int {
   633  		if tracer.errorValue != nil {
   634  			ctx.PushString(*tracer.errorValue)
   635  		} else {
   636  			ctx.PushUndefined()
   637  		}
   638  		return 1
   639  	})
   640  	tracer.vm.PutPropString(logObject, "getError")
   641  
   642  	tracer.vm.PutPropString(tracer.stateObject, "log")
   643  
   644  	tracer.frame.pushObject(tracer.vm)
   645  	tracer.vm.PutPropString(tracer.stateObject, "frame")
   646  
   647  	tracer.frameResult.pushObject(tracer.vm)
   648  	tracer.vm.PutPropString(tracer.stateObject, "frameResult")
   649  
   650  	tracer.dbWrapper.pushObject(tracer.vm)
   651  	tracer.vm.PutPropString(tracer.stateObject, "db")
   652  
   653  	return tracer, nil
   654  }
   655  
   656  // Stop terminates execution of the tracer at the first opportune moment.
   657  func (jst *jsTracer) Stop(err error) {
   658  	jst.reason = err
   659  	atomic.StoreUint32(&jst.interrupt, 1)
   660  }
   661  
   662  // call executes a method on a JS object, catching any errors, formatting and
   663  // returning them as error objects.
   664  func (jst *jsTracer) call(noret bool, method string, args ...string) (json.RawMessage, error) {
   665  	// Execute the JavaScript call and return any error
   666  	jst.vm.PushString(method)
   667  	for _, arg := range args {
   668  		jst.vm.GetPropString(jst.stateObject, arg)
   669  	}
   670  	code := jst.vm.PcallProp(jst.tracerObject, len(args))
   671  	defer jst.vm.Pop()
   672  
   673  	if code != 0 {
   674  		err := jst.vm.SafeToString(-1)
   675  		return nil, errors.New(err)
   676  	}
   677  	// No error occurred, extract return value and return
   678  	if noret {
   679  		return nil, nil
   680  	}
   681  	// Push a JSON marshaller onto the stack. We can't marshal from the out-
   682  	// side because duktape can crash on large nestings and we can't catch
   683  	// C++ exceptions ourselves from Go. TODO(karalabe): Yuck, why wrap?!
   684  	jst.vm.PushString("(JSON.stringify)")
   685  	jst.vm.Eval()
   686  
   687  	jst.vm.Swap(-1, -2)
   688  	if code = jst.vm.Pcall(1); code != 0 {
   689  		err := jst.vm.SafeToString(-1)
   690  		return nil, errors.New(err)
   691  	}
   692  	return json.RawMessage(jst.vm.SafeToString(-1)), nil
   693  }
   694  
   695  func wrapError(context string, err error) error {
   696  	return fmt.Errorf("%v    in server-side tracer function '%v'", err, context)
   697  }
   698  
   699  // CaptureStart implements the Tracer interface to initialize the tracing operation.
   700  func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
   701  	//
   702  	//jst.env = env
   703  	//jst.ctx["type"] = "CALL"
   704  	//if create {
   705  	//	jst.ctx["type"] = "CREATE"
   706  	//}
   707  	//jst.ctx["from"] = from
   708  	//jst.ctx["to"] = to
   709  	//jst.ctx["input"] = input
   710  	//jst.ctx["gas"] = gas
   711  	//jst.ctx["gasPrice"] = env.TxContext.GasPrice
   712  	//jst.ctx["value"] = value
   713  	//
   714  	//// Initialize the context
   715  	//jst.ctx["block"] = env.Context.BlockNumber.Uint64()
   716  	//jst.dbWrapper.db = env.StateDB
   717  	//// Update list of precompiles based on current block
   718  	//rules := env.ChainConfig().Rules(env.Context.BlockNumber)
   719  	//jst.activePrecompiles = vm.ActivePrecompiles(rules)
   720  	//
   721  	//// Compute intrinsic gas
   722  	//isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
   723  	//isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)
   724  	//intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
   725  	//if err != nil {
   726  	//	return
   727  	//}
   728  	//jst.ctx["intrinsicGas"] = intrinsicGas
   729  
   730  	jst.env = env
   731  
   732  	jst.ctx["type"] = "CALL"
   733  	if create {
   734  		jst.ctx["type"] = "CREATE"
   735  	}
   736  	jst.ctx["from"] = from
   737  	jst.ctx["to"] = to
   738  	jst.ctx["input"] = input
   739  	jst.ctx["gas"] = gas
   740  	jst.ctx["value"] = value
   741  
   742  }
   743  
   744  // CaptureState implements the Tracer interface to trace a single step of VM execution.
   745  
   746  //func (jst *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
   747  func (jst *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
   748  	if !jst.traceSteps {
   749  		return
   750  	}
   751  	if jst.err != nil {
   752  		return
   753  	}
   754  	// If tracing was interrupted, set the error and stop
   755  	if atomic.LoadUint32(&jst.interrupt) > 0 {
   756  		jst.err = jst.reason
   757  		jst.env.Cancel()
   758  		return
   759  	}
   760  	jst.opWrapper.op = op
   761  	jst.stackWrapper.stack = scope.Stack
   762  	jst.memoryWrapper.memory = scope.Memory
   763  	jst.contractWrapper.contract = scope.Contract
   764  
   765  	*jst.pcValue = uint(pc)
   766  	*jst.gasValue = uint(gas)
   767  	*jst.costValue = uint(cost)
   768  	*jst.depthValue = uint(depth)
   769  	*jst.refundValue = uint(jst.env.StateDB.GetRefund())
   770  
   771  	jst.errorValue = nil
   772  	if err != nil {
   773  		jst.errorValue = new(string)
   774  		*jst.errorValue = err.Error()
   775  	}
   776  
   777  	if _, err := jst.call(true, "step", "log", "db"); err != nil {
   778  		jst.err = wrapError("step", err)
   779  	}
   780  
   781  }
   782  
   783  // CaptureFault implements the Tracer interface to trace an execution fault
   784  // while running an opcode.
   785  
   786  func (jst *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
   787  	if jst.err != nil {
   788  		return
   789  	}
   790  	// Apart from the error, everything matches the previous invocation
   791  	jst.errorValue = new(string)
   792  	*jst.errorValue = err.Error()
   793  
   794  	if _, err := jst.call(true, "fault", "log", "db"); err != nil {
   795  		jst.err = wrapError("fault", err)
   796  	}
   797  }
   798  
   799  // CaptureEnd is called after the call finishes to finalize the tracing.
   800  func (jst *jsTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
   801  	jst.ctx["output"] = output
   802  	jst.ctx["time"] = t.String()
   803  	jst.ctx["gasUsed"] = gasUsed
   804  
   805  	if err != nil {
   806  		jst.ctx["error"] = err.Error()
   807  	}
   808  }
   809  
   810  // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
   811  func (jst *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
   812  	if !jst.traceCallFrames {
   813  		return
   814  	}
   815  	if jst.err != nil {
   816  		return
   817  	}
   818  	// If tracing was interrupted, set the error and stop
   819  	if atomic.LoadUint32(&jst.interrupt) > 0 {
   820  		jst.err = jst.reason
   821  		return
   822  	}
   823  
   824  	*jst.frame.typ = typ.String()
   825  	*jst.frame.from = from
   826  	*jst.frame.to = to
   827  	jst.frame.input = common.CopyBytes(input)
   828  	*jst.frame.gas = uint(gas)
   829  	jst.frame.value = nil
   830  	if value != nil {
   831  		jst.frame.value = new(big.Int).SetBytes(value.Bytes())
   832  	}
   833  
   834  	if _, err := jst.call(true, "enter", "frame"); err != nil {
   835  		jst.err = wrapError("enter", err)
   836  	}
   837  }
   838  
   839  // CaptureExit is called when EVM exits a scope, even if the scope didn't
   840  // execute any code.
   841  func (jst *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
   842  	if !jst.traceCallFrames {
   843  		return
   844  	}
   845  	// If tracing was interrupted, set the error and stop
   846  	if atomic.LoadUint32(&jst.interrupt) > 0 {
   847  		jst.err = jst.reason
   848  		return
   849  	}
   850  
   851  	jst.frameResult.output = common.CopyBytes(output)
   852  	*jst.frameResult.gasUsed = uint(gasUsed)
   853  	jst.frameResult.errorValue = nil
   854  	if err != nil {
   855  		jst.frameResult.errorValue = new(string)
   856  		*jst.frameResult.errorValue = err.Error()
   857  	}
   858  
   859  	if _, err := jst.call(true, "exit", "frameResult"); err != nil {
   860  		jst.err = wrapError("exit", err)
   861  	}
   862  }
   863  
   864  // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
   865  func (jst *jsTracer) GetResult() (json.RawMessage, error) {
   866  	// Transform the context into a JavaScript object and inject into the state
   867  	obj := jst.vm.PushObject()
   868  
   869  	for key, val := range jst.ctx {
   870  		jst.addToObj(obj, key, val)
   871  	}
   872  	jst.vm.PutPropString(jst.stateObject, "ctx")
   873  
   874  	// Finalize the trace and return the results
   875  	result, err := jst.call(false, "result", "ctx", "db")
   876  	if err != nil {
   877  		jst.err = wrapError("result", err)
   878  	}
   879  	// Clean up the JavaScript environment
   880  	jst.vm.DestroyHeap()
   881  	jst.vm.Destroy()
   882  
   883  	return result, jst.err
   884  }
   885  
   886  // addToObj pushes a field to a JS object.
   887  func (jst *jsTracer) addToObj(obj int, key string, val interface{}) {
   888  	pushValue(jst.vm, val)
   889  	jst.vm.PutPropString(obj, key)
   890  }