github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/eth/tracers/tracer.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tracers
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"sync/atomic"
    25  	"time"
    26  	"unsafe"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/common/hexutil"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/vm"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/log"
    34  	"gopkg.in/olebedev/go-duktape.v3"
    35  )
    36  
    37  // bigIntegerJS is the minified version of https://github.com/peterolson/BigInteger.js.
    38  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`
    39  
    40  // makeSlice convert an unsafe memory pointer with the given type into a Go byte
    41  // slice.
    42  //
    43  // Note, the returned slice uses the same memory area as the input arguments.
    44  // If those are duktape stack items, popping them off **will** make the slice
    45  // contents change.
    46  func makeSlice(ptr unsafe.Pointer, size uint) []byte {
    47  	var sl = struct {
    48  		addr uintptr
    49  		len  int
    50  		cap  int
    51  	}{uintptr(ptr), int(size), int(size)}
    52  
    53  	return *(*[]byte)(unsafe.Pointer(&sl))
    54  }
    55  
    56  // popSlice pops a buffer off the JavaScript stack and returns it as a slice.
    57  func popSlice(ctx *duktape.Context) []byte {
    58  	blob := common.CopyBytes(makeSlice(ctx.GetBuffer(-1)))
    59  	ctx.Pop()
    60  	return blob
    61  }
    62  
    63  // pushBigInt create a JavaScript BigInteger in the VM.
    64  func pushBigInt(n *big.Int, ctx *duktape.Context) {
    65  	ctx.GetGlobalString("bigInt")
    66  	ctx.PushString(n.String())
    67  	ctx.Call(1)
    68  }
    69  
    70  // opWrapper provides a JavaScript wrapper around OpCode.
    71  type opWrapper struct {
    72  	op vm.OpCode
    73  }
    74  
    75  // pushObject assembles a JSVM object wrapping a swappable opcode and pushes it
    76  // onto the VM stack.
    77  func (ow *opWrapper) pushObject(vm *duktape.Context) {
    78  	obj := vm.PushObject()
    79  
    80  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(int(ow.op)); return 1 })
    81  	vm.PutPropString(obj, "toNumber")
    82  
    83  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushString(ow.op.String()); return 1 })
    84  	vm.PutPropString(obj, "toString")
    85  
    86  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushBoolean(ow.op.IsPush()); return 1 })
    87  	vm.PutPropString(obj, "isPush")
    88  }
    89  
    90  // memoryWrapper provides a JavaScript wrapper around vm.Memory.
    91  type memoryWrapper struct {
    92  	memory *vm.Memory
    93  }
    94  
    95  // slice returns the requested range of memory as a byte slice.
    96  func (mw *memoryWrapper) slice(begin, end int64) []byte {
    97  	if end == begin {
    98  		return []byte{}
    99  	}
   100  	if end < begin || begin < 0 {
   101  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   102  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   103  		log.Warn("Tracer accessed out of bound memory", "offset", begin, "end", end)
   104  		return nil
   105  	}
   106  	if mw.memory.Len() < int(end) {
   107  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   108  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   109  		log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", begin, "size", end-begin)
   110  		return nil
   111  	}
   112  	return mw.memory.GetCopy(begin, end-begin)
   113  }
   114  
   115  // getUint returns the 32 bytes at the specified address interpreted as a uint.
   116  func (mw *memoryWrapper) getUint(addr int64) *big.Int {
   117  	if mw.memory.Len() < int(addr)+32 || addr < 0 {
   118  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   119  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   120  		log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", addr, "size", 32)
   121  		return new(big.Int)
   122  	}
   123  	return new(big.Int).SetBytes(mw.memory.GetPtr(addr, 32))
   124  }
   125  
   126  // pushObject assembles a JSVM object wrapping a swappable memory and pushes it
   127  // onto the VM stack.
   128  func (mw *memoryWrapper) pushObject(vm *duktape.Context) {
   129  	obj := vm.PushObject()
   130  
   131  	// Generate the `slice` method which takes two ints and returns a buffer
   132  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   133  		blob := mw.slice(int64(ctx.GetInt(-2)), int64(ctx.GetInt(-1)))
   134  		ctx.Pop2()
   135  
   136  		ptr := ctx.PushFixedBuffer(len(blob))
   137  		copy(makeSlice(ptr, uint(len(blob))), blob)
   138  		return 1
   139  	})
   140  	vm.PutPropString(obj, "slice")
   141  
   142  	// Generate the `getUint` method which takes an int and returns a bigint
   143  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   144  		offset := int64(ctx.GetInt(-1))
   145  		ctx.Pop()
   146  
   147  		pushBigInt(mw.getUint(offset), ctx)
   148  		return 1
   149  	})
   150  	vm.PutPropString(obj, "getUint")
   151  }
   152  
   153  // stackWrapper provides a JavaScript wrapper around vm.Stack.
   154  type stackWrapper struct {
   155  	stack *vm.Stack
   156  }
   157  
   158  // peek returns the nth-from-the-top element of the stack.
   159  func (sw *stackWrapper) peek(idx int) *big.Int {
   160  	if len(sw.stack.Data()) <= idx || idx < 0 {
   161  		// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   162  		// runtime goes belly up https://github.com/golang/go/issues/15639.
   163  		log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
   164  		return new(big.Int)
   165  	}
   166  	return sw.stack.Back(idx).ToBig()
   167  }
   168  
   169  // pushObject assembles a JSVM object wrapping a swappable stack and pushes it
   170  // onto the VM stack.
   171  func (sw *stackWrapper) pushObject(vm *duktape.Context) {
   172  	obj := vm.PushObject()
   173  
   174  	vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(len(sw.stack.Data())); return 1 })
   175  	vm.PutPropString(obj, "length")
   176  
   177  	// Generate the `peek` method which takes an int and returns a bigint
   178  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   179  		offset := ctx.GetInt(-1)
   180  		ctx.Pop()
   181  
   182  		pushBigInt(sw.peek(offset), ctx)
   183  		return 1
   184  	})
   185  	vm.PutPropString(obj, "peek")
   186  }
   187  
   188  // dbWrapper provides a JavaScript wrapper around vm.Database.
   189  type dbWrapper struct {
   190  	db vm.StateDB
   191  }
   192  
   193  // pushObject assembles a JSVM object wrapping a swappable database and pushes it
   194  // onto the VM stack.
   195  func (dw *dbWrapper) pushObject(vm *duktape.Context) {
   196  	obj := vm.PushObject()
   197  
   198  	// Push the wrapper for statedb.GetBalance
   199  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   200  		pushBigInt(dw.db.GetBalance(common.BytesToAddress(popSlice(ctx))), ctx)
   201  		return 1
   202  	})
   203  	vm.PutPropString(obj, "getBalance")
   204  
   205  	// Push the wrapper for statedb.GetNonce
   206  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   207  		ctx.PushInt(int(dw.db.GetNonce(common.BytesToAddress(popSlice(ctx)))))
   208  		return 1
   209  	})
   210  	vm.PutPropString(obj, "getNonce")
   211  
   212  	// Push the wrapper for statedb.GetCode
   213  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   214  		code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx)))
   215  
   216  		ptr := ctx.PushFixedBuffer(len(code))
   217  		copy(makeSlice(ptr, uint(len(code))), code)
   218  		return 1
   219  	})
   220  	vm.PutPropString(obj, "getCode")
   221  
   222  	// Push the wrapper for statedb.GetState
   223  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   224  		hash := popSlice(ctx)
   225  		addr := popSlice(ctx)
   226  
   227  		state := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash))
   228  
   229  		ptr := ctx.PushFixedBuffer(len(state))
   230  		copy(makeSlice(ptr, uint(len(state))), state[:])
   231  		return 1
   232  	})
   233  	vm.PutPropString(obj, "getState")
   234  
   235  	// Push the wrapper for statedb.Exists
   236  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   237  		ctx.PushBoolean(dw.db.Exist(common.BytesToAddress(popSlice(ctx))))
   238  		return 1
   239  	})
   240  	vm.PutPropString(obj, "exists")
   241  }
   242  
   243  // contractWrapper provides a JavaScript wrapper around vm.Contract
   244  type contractWrapper struct {
   245  	contract *vm.Contract
   246  }
   247  
   248  // pushObject assembles a JSVM object wrapping a swappable contract and pushes it
   249  // onto the VM stack.
   250  func (cw *contractWrapper) pushObject(vm *duktape.Context) {
   251  	obj := vm.PushObject()
   252  
   253  	// Push the wrapper for contract.Caller
   254  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   255  		ptr := ctx.PushFixedBuffer(20)
   256  		copy(makeSlice(ptr, 20), cw.contract.Caller().Bytes())
   257  		return 1
   258  	})
   259  	vm.PutPropString(obj, "getCaller")
   260  
   261  	// Push the wrapper for contract.Address
   262  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   263  		ptr := ctx.PushFixedBuffer(20)
   264  		copy(makeSlice(ptr, 20), cw.contract.Address().Bytes())
   265  		return 1
   266  	})
   267  	vm.PutPropString(obj, "getAddress")
   268  
   269  	// Push the wrapper for contract.Value
   270  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   271  		pushBigInt(cw.contract.Value(), ctx)
   272  		return 1
   273  	})
   274  	vm.PutPropString(obj, "getValue")
   275  
   276  	// Push the wrapper for contract.Input
   277  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   278  		blob := cw.contract.Input
   279  
   280  		ptr := ctx.PushFixedBuffer(len(blob))
   281  		copy(makeSlice(ptr, uint(len(blob))), blob)
   282  		return 1
   283  	})
   284  	vm.PutPropString(obj, "getInput")
   285  }
   286  
   287  type frame struct {
   288  	typ   *string
   289  	from  *common.Address
   290  	to    *common.Address
   291  	input []byte
   292  	gas   *uint
   293  	value *big.Int
   294  }
   295  
   296  func newFrame() *frame {
   297  	return &frame{
   298  		typ:  new(string),
   299  		from: new(common.Address),
   300  		to:   new(common.Address),
   301  		gas:  new(uint),
   302  	}
   303  }
   304  
   305  func (f *frame) pushObject(vm *duktape.Context) {
   306  	obj := vm.PushObject()
   307  
   308  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.typ); return 1 })
   309  	vm.PutPropString(obj, "getType")
   310  
   311  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.from); return 1 })
   312  	vm.PutPropString(obj, "getFrom")
   313  
   314  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.to); return 1 })
   315  	vm.PutPropString(obj, "getTo")
   316  
   317  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, f.input); return 1 })
   318  	vm.PutPropString(obj, "getInput")
   319  
   320  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.gas); return 1 })
   321  	vm.PutPropString(obj, "getGas")
   322  
   323  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   324  		if f.value != nil {
   325  			pushValue(ctx, f.value)
   326  		} else {
   327  			ctx.PushUndefined()
   328  		}
   329  		return 1
   330  	})
   331  	vm.PutPropString(obj, "getValue")
   332  }
   333  
   334  type frameResult struct {
   335  	gasUsed    *uint
   336  	output     []byte
   337  	errorValue *string
   338  }
   339  
   340  func newFrameResult() *frameResult {
   341  	return &frameResult{
   342  		gasUsed: new(uint),
   343  	}
   344  }
   345  
   346  func (r *frameResult) pushObject(vm *duktape.Context) {
   347  	obj := vm.PushObject()
   348  
   349  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *r.gasUsed); return 1 })
   350  	vm.PutPropString(obj, "getGasUsed")
   351  
   352  	vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, r.output); return 1 })
   353  	vm.PutPropString(obj, "getOutput")
   354  
   355  	vm.PushGoFunction(func(ctx *duktape.Context) int {
   356  		if r.errorValue != nil {
   357  			pushValue(ctx, *r.errorValue)
   358  		} else {
   359  			ctx.PushUndefined()
   360  		}
   361  		return 1
   362  	})
   363  	vm.PutPropString(obj, "getError")
   364  }
   365  
   366  // Tracer provides an implementation of Tracer that evaluates a Javascript
   367  // function for each VM execution step.
   368  type Tracer struct {
   369  	vm *duktape.Context // Javascript VM instance
   370  
   371  	tracerObject int // Stack index of the tracer JavaScript object
   372  	stateObject  int // Stack index of the global state to pull arguments from
   373  
   374  	opWrapper       *opWrapper       // Wrapper around the VM opcode
   375  	stackWrapper    *stackWrapper    // Wrapper around the VM stack
   376  	memoryWrapper   *memoryWrapper   // Wrapper around the VM memory
   377  	contractWrapper *contractWrapper // Wrapper around the contract object
   378  	dbWrapper       *dbWrapper       // Wrapper around the VM environment
   379  
   380  	pcValue     *uint   // Swappable pc value wrapped by a log accessor
   381  	gasValue    *uint   // Swappable gas value wrapped by a log accessor
   382  	costValue   *uint   // Swappable cost value wrapped by a log accessor
   383  	depthValue  *uint   // Swappable depth value wrapped by a log accessor
   384  	errorValue  *string // Swappable error value wrapped by a log accessor
   385  	refundValue *uint   // Swappable refund value wrapped by a log accessor
   386  
   387  	frame       *frame       // Represents entry into call frame. Fields are swappable
   388  	frameResult *frameResult // Represents exit from a call frame. Fields are swappable
   389  
   390  	ctx map[string]interface{} // Transaction context gathered throughout execution
   391  	err error                  // Error, if one has occurred
   392  
   393  	interrupt uint32 // Atomic flag to signal execution interruption
   394  	reason    error  // Textual reason for the interruption
   395  
   396  	activePrecompiles []common.Address // Updated on CaptureStart based on given rules
   397  	traceSteps        bool             // When true, will invoke step() on each opcode
   398  	traceCallFrames   bool             // When true, will invoke enter() and exit() js funcs
   399  }
   400  
   401  // Context contains some contextual infos for a transaction execution that is not
   402  // available from within the EVM object.
   403  type Context struct {
   404  	BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call)
   405  	TxIndex   int         // Index of the transaction within a block (zero if dangling tx or call)
   406  	TxHash    common.Hash // Hash of the transaction being traced (zero if dangling call)
   407  }
   408  
   409  // New instantiates a new tracer instance. code specifies a Javascript snippet,
   410  // which must evaluate to an expression returning an object with 'step', 'fault'
   411  // and 'result' functions.
   412  func New(code string, ctx *Context) (*Tracer, error) {
   413  	// Resolve any tracers by name and assemble the tracer object
   414  	if tracer, ok := tracer(code); ok {
   415  		code = tracer
   416  	}
   417  	tracer := &Tracer{
   418  		vm:              duktape.New(),
   419  		ctx:             make(map[string]interface{}),
   420  		opWrapper:       new(opWrapper),
   421  		stackWrapper:    new(stackWrapper),
   422  		memoryWrapper:   new(memoryWrapper),
   423  		contractWrapper: new(contractWrapper),
   424  		dbWrapper:       new(dbWrapper),
   425  		pcValue:         new(uint),
   426  		gasValue:        new(uint),
   427  		costValue:       new(uint),
   428  		depthValue:      new(uint),
   429  		refundValue:     new(uint),
   430  		frame:           newFrame(),
   431  		frameResult:     newFrameResult(),
   432  	}
   433  	if ctx.BlockHash != (common.Hash{}) {
   434  		tracer.ctx["blockHash"] = ctx.BlockHash
   435  
   436  		if ctx.TxHash != (common.Hash{}) {
   437  			tracer.ctx["txIndex"] = ctx.TxIndex
   438  			tracer.ctx["txHash"] = ctx.TxHash
   439  		}
   440  	}
   441  	// Set up builtins for this environment
   442  	tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int {
   443  		ctx.PushString(hexutil.Encode(popSlice(ctx)))
   444  		return 1
   445  	})
   446  	tracer.vm.PushGlobalGoFunction("toWord", func(ctx *duktape.Context) int {
   447  		var word common.Hash
   448  		if ptr, size := ctx.GetBuffer(-1); ptr != nil {
   449  			word = common.BytesToHash(makeSlice(ptr, size))
   450  		} else {
   451  			word = common.HexToHash(ctx.GetString(-1))
   452  		}
   453  		ctx.Pop()
   454  		copy(makeSlice(ctx.PushFixedBuffer(32), 32), word[:])
   455  		return 1
   456  	})
   457  	tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *duktape.Context) int {
   458  		var addr common.Address
   459  		if ptr, size := ctx.GetBuffer(-1); ptr != nil {
   460  			addr = common.BytesToAddress(makeSlice(ptr, size))
   461  		} else {
   462  			addr = common.HexToAddress(ctx.GetString(-1))
   463  		}
   464  		ctx.Pop()
   465  		copy(makeSlice(ctx.PushFixedBuffer(20), 20), addr[:])
   466  		return 1
   467  	})
   468  	tracer.vm.PushGlobalGoFunction("toContract", func(ctx *duktape.Context) int {
   469  		var from common.Address
   470  		if ptr, size := ctx.GetBuffer(-2); ptr != nil {
   471  			from = common.BytesToAddress(makeSlice(ptr, size))
   472  		} else {
   473  			from = common.HexToAddress(ctx.GetString(-2))
   474  		}
   475  		nonce := uint64(ctx.GetInt(-1))
   476  		ctx.Pop2()
   477  
   478  		contract := crypto.CreateAddress(from, nonce)
   479  		copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
   480  		return 1
   481  	})
   482  	tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int {
   483  		var from common.Address
   484  		if ptr, size := ctx.GetBuffer(-3); ptr != nil {
   485  			from = common.BytesToAddress(makeSlice(ptr, size))
   486  		} else {
   487  			from = common.HexToAddress(ctx.GetString(-3))
   488  		}
   489  		// Retrieve salt hex string from js stack
   490  		salt := common.HexToHash(ctx.GetString(-2))
   491  		// Retrieve code slice from js stack
   492  		var code []byte
   493  		if ptr, size := ctx.GetBuffer(-1); ptr != nil {
   494  			code = common.CopyBytes(makeSlice(ptr, size))
   495  		} else {
   496  			code = common.FromHex(ctx.GetString(-1))
   497  		}
   498  		codeHash := crypto.Keccak256(code)
   499  		ctx.Pop3()
   500  		contract := crypto.CreateAddress2(from, salt, codeHash)
   501  		copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
   502  		return 1
   503  	})
   504  	tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
   505  		addr := common.BytesToAddress(popSlice(ctx))
   506  		for _, p := range tracer.activePrecompiles {
   507  			if p == addr {
   508  				ctx.PushBoolean(true)
   509  				return 1
   510  			}
   511  		}
   512  		ctx.PushBoolean(false)
   513  		return 1
   514  	})
   515  	tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int {
   516  		start, end := ctx.GetInt(-2), ctx.GetInt(-1)
   517  		ctx.Pop2()
   518  
   519  		blob := popSlice(ctx)
   520  		size := end - start
   521  
   522  		if start < 0 || start > end || end > len(blob) {
   523  			// TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go
   524  			// runtime goes belly up https://github.com/golang/go/issues/15639.
   525  			log.Warn("Tracer accessed out of bound memory", "available", len(blob), "offset", start, "size", size)
   526  			ctx.PushFixedBuffer(0)
   527  			return 1
   528  		}
   529  		copy(makeSlice(ctx.PushFixedBuffer(size), uint(size)), blob[start:end])
   530  		return 1
   531  	})
   532  	// Push the JavaScript tracer as object #0 onto the JSVM stack and validate it
   533  	if err := tracer.vm.PevalString("(" + code + ")"); err != nil {
   534  		log.Warn("Failed to compile tracer", "err", err)
   535  		return nil, err
   536  	}
   537  	tracer.tracerObject = 0 // yeah, nice, eval can't return the index itself
   538  
   539  	hasStep := tracer.vm.GetPropString(tracer.tracerObject, "step")
   540  	tracer.vm.Pop()
   541  
   542  	if !tracer.vm.GetPropString(tracer.tracerObject, "fault") {
   543  		return nil, fmt.Errorf("trace object must expose a function fault()")
   544  	}
   545  	tracer.vm.Pop()
   546  
   547  	if !tracer.vm.GetPropString(tracer.tracerObject, "result") {
   548  		return nil, fmt.Errorf("trace object must expose a function result()")
   549  	}
   550  	tracer.vm.Pop()
   551  
   552  	hasEnter := tracer.vm.GetPropString(tracer.tracerObject, "enter")
   553  	tracer.vm.Pop()
   554  	hasExit := tracer.vm.GetPropString(tracer.tracerObject, "exit")
   555  	tracer.vm.Pop()
   556  
   557  	if hasEnter != hasExit {
   558  		return nil, fmt.Errorf("trace object must expose either both or none of enter() and exit()")
   559  	}
   560  	if !hasStep {
   561  		// If there's no step function, the enter and exit must be present
   562  		if !hasEnter {
   563  			return nil, fmt.Errorf("trace object must expose either step() or both enter() and exit()")
   564  		}
   565  	}
   566  	tracer.traceCallFrames = hasEnter
   567  	tracer.traceSteps = hasStep
   568  
   569  	// Tracer is valid, inject the big int library to access large numbers
   570  	tracer.vm.EvalString(bigIntegerJS)
   571  	tracer.vm.PutGlobalString("bigInt")
   572  
   573  	// Push the global environment state as object #1 into the JSVM stack
   574  	tracer.stateObject = tracer.vm.PushObject()
   575  
   576  	logObject := tracer.vm.PushObject()
   577  
   578  	tracer.opWrapper.pushObject(tracer.vm)
   579  	tracer.vm.PutPropString(logObject, "op")
   580  
   581  	tracer.stackWrapper.pushObject(tracer.vm)
   582  	tracer.vm.PutPropString(logObject, "stack")
   583  
   584  	tracer.memoryWrapper.pushObject(tracer.vm)
   585  	tracer.vm.PutPropString(logObject, "memory")
   586  
   587  	tracer.contractWrapper.pushObject(tracer.vm)
   588  	tracer.vm.PutPropString(logObject, "contract")
   589  
   590  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.pcValue); return 1 })
   591  	tracer.vm.PutPropString(logObject, "getPC")
   592  
   593  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.gasValue); return 1 })
   594  	tracer.vm.PutPropString(logObject, "getGas")
   595  
   596  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.costValue); return 1 })
   597  	tracer.vm.PutPropString(logObject, "getCost")
   598  
   599  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.depthValue); return 1 })
   600  	tracer.vm.PutPropString(logObject, "getDepth")
   601  
   602  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.refundValue); return 1 })
   603  	tracer.vm.PutPropString(logObject, "getRefund")
   604  
   605  	tracer.vm.PushGoFunction(func(ctx *duktape.Context) int {
   606  		if tracer.errorValue != nil {
   607  			ctx.PushString(*tracer.errorValue)
   608  		} else {
   609  			ctx.PushUndefined()
   610  		}
   611  		return 1
   612  	})
   613  	tracer.vm.PutPropString(logObject, "getError")
   614  
   615  	tracer.vm.PutPropString(tracer.stateObject, "log")
   616  
   617  	tracer.frame.pushObject(tracer.vm)
   618  	tracer.vm.PutPropString(tracer.stateObject, "frame")
   619  
   620  	tracer.frameResult.pushObject(tracer.vm)
   621  	tracer.vm.PutPropString(tracer.stateObject, "frameResult")
   622  
   623  	tracer.dbWrapper.pushObject(tracer.vm)
   624  	tracer.vm.PutPropString(tracer.stateObject, "db")
   625  
   626  	return tracer, nil
   627  }
   628  
   629  // Stop terminates execution of the tracer at the first opportune moment.
   630  func (jst *Tracer) Stop(err error) {
   631  	jst.reason = err
   632  	atomic.StoreUint32(&jst.interrupt, 1)
   633  }
   634  
   635  // call executes a method on a JS object, catching any errors, formatting and
   636  // returning them as error objects.
   637  func (jst *Tracer) call(noret bool, method string, args ...string) (json.RawMessage, error) {
   638  	// Execute the JavaScript call and return any error
   639  	jst.vm.PushString(method)
   640  	for _, arg := range args {
   641  		jst.vm.GetPropString(jst.stateObject, arg)
   642  	}
   643  	code := jst.vm.PcallProp(jst.tracerObject, len(args))
   644  	defer jst.vm.Pop()
   645  
   646  	if code != 0 {
   647  		err := jst.vm.SafeToString(-1)
   648  		return nil, errors.New(err)
   649  	}
   650  	// No error occurred, extract return value and return
   651  	if noret {
   652  		return nil, nil
   653  	}
   654  	// Push a JSON marshaller onto the stack. We can't marshal from the out-
   655  	// side because duktape can crash on large nestings and we can't catch
   656  	// C++ exceptions ourselves from Go. TODO(karalabe): Yuck, why wrap?!
   657  	jst.vm.PushString("(JSON.stringify)")
   658  	jst.vm.Eval()
   659  
   660  	jst.vm.Swap(-1, -2)
   661  	if code = jst.vm.Pcall(1); code != 0 {
   662  		err := jst.vm.SafeToString(-1)
   663  		return nil, errors.New(err)
   664  	}
   665  	return json.RawMessage(jst.vm.SafeToString(-1)), nil
   666  }
   667  
   668  func wrapError(context string, err error) error {
   669  	return fmt.Errorf("%v    in server-side tracer function '%v'", err, context)
   670  }
   671  
   672  // CaptureStart implements the Tracer interface to initialize the tracing operation.
   673  func (jst *Tracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
   674  	jst.ctx["type"] = "CALL"
   675  	if create {
   676  		jst.ctx["type"] = "CREATE"
   677  	}
   678  	jst.ctx["from"] = from
   679  	jst.ctx["to"] = to
   680  	jst.ctx["input"] = input
   681  	jst.ctx["gas"] = gas
   682  	jst.ctx["gasPrice"] = env.TxContext.GasPrice
   683  	jst.ctx["value"] = value
   684  
   685  	// Initialize the context
   686  	jst.ctx["block"] = env.Context.BlockNumber.Uint64()
   687  	jst.dbWrapper.db = env.StateDB
   688  	// Update list of precompiles based on current block
   689  	rules := env.ChainConfig().Rules(env.Context.BlockNumber)
   690  	jst.activePrecompiles = vm.ActivePrecompiles(rules)
   691  
   692  	// Compute intrinsic gas
   693  	isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
   694  	isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)
   695  	intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
   696  	if err != nil {
   697  		return
   698  	}
   699  	jst.ctx["intrinsicGas"] = intrinsicGas
   700  }
   701  
   702  // CaptureState implements the Tracer interface to trace a single step of VM execution.
   703  func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
   704  	if !jst.traceSteps {
   705  		return
   706  	}
   707  	if jst.err != nil {
   708  		return
   709  	}
   710  	// If tracing was interrupted, set the error and stop
   711  	if atomic.LoadUint32(&jst.interrupt) > 0 {
   712  		jst.err = jst.reason
   713  		env.Cancel()
   714  		return
   715  	}
   716  	jst.opWrapper.op = op
   717  	jst.stackWrapper.stack = scope.Stack
   718  	jst.memoryWrapper.memory = scope.Memory
   719  	jst.contractWrapper.contract = scope.Contract
   720  
   721  	*jst.pcValue = uint(pc)
   722  	*jst.gasValue = uint(gas)
   723  	*jst.costValue = uint(cost)
   724  	*jst.depthValue = uint(depth)
   725  	*jst.refundValue = uint(env.StateDB.GetRefund())
   726  
   727  	jst.errorValue = nil
   728  	if err != nil {
   729  		jst.errorValue = new(string)
   730  		*jst.errorValue = err.Error()
   731  	}
   732  
   733  	if _, err := jst.call(true, "step", "log", "db"); err != nil {
   734  		jst.err = wrapError("step", err)
   735  	}
   736  }
   737  
   738  // CaptureFault implements the Tracer interface to trace an execution fault
   739  func (jst *Tracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
   740  	if jst.err != nil {
   741  		return
   742  	}
   743  	// Apart from the error, everything matches the previous invocation
   744  	jst.errorValue = new(string)
   745  	*jst.errorValue = err.Error()
   746  
   747  	if _, err := jst.call(true, "fault", "log", "db"); err != nil {
   748  		jst.err = wrapError("fault", err)
   749  	}
   750  }
   751  
   752  // CaptureEnd is called after the call finishes to finalize the tracing.
   753  func (jst *Tracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
   754  	jst.ctx["output"] = output
   755  	jst.ctx["time"] = t.String()
   756  	jst.ctx["gasUsed"] = gasUsed
   757  
   758  	if err != nil {
   759  		jst.ctx["error"] = err.Error()
   760  	}
   761  }
   762  
   763  // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
   764  func (jst *Tracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
   765  	if !jst.traceCallFrames {
   766  		return
   767  	}
   768  	if jst.err != nil {
   769  		return
   770  	}
   771  	// If tracing was interrupted, set the error and stop
   772  	if atomic.LoadUint32(&jst.interrupt) > 0 {
   773  		jst.err = jst.reason
   774  		return
   775  	}
   776  
   777  	*jst.frame.typ = typ.String()
   778  	*jst.frame.from = from
   779  	*jst.frame.to = to
   780  	jst.frame.input = common.CopyBytes(input)
   781  	*jst.frame.gas = uint(gas)
   782  	jst.frame.value = nil
   783  	if value != nil {
   784  		jst.frame.value = new(big.Int).SetBytes(value.Bytes())
   785  	}
   786  
   787  	if _, err := jst.call(true, "enter", "frame"); err != nil {
   788  		jst.err = wrapError("enter", err)
   789  	}
   790  }
   791  
   792  // CaptureExit is called when EVM exits a scope, even if the scope didn't
   793  // execute any code.
   794  func (jst *Tracer) CaptureExit(output []byte, gasUsed uint64, err error) {
   795  	if !jst.traceCallFrames {
   796  		return
   797  	}
   798  	// If tracing was interrupted, set the error and stop
   799  	if atomic.LoadUint32(&jst.interrupt) > 0 {
   800  		jst.err = jst.reason
   801  		return
   802  	}
   803  
   804  	jst.frameResult.output = common.CopyBytes(output)
   805  	*jst.frameResult.gasUsed = uint(gasUsed)
   806  	jst.frameResult.errorValue = nil
   807  	if err != nil {
   808  		jst.frameResult.errorValue = new(string)
   809  		*jst.frameResult.errorValue = err.Error()
   810  	}
   811  
   812  	if _, err := jst.call(true, "exit", "frameResult"); err != nil {
   813  		jst.err = wrapError("exit", err)
   814  	}
   815  }
   816  
   817  // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
   818  func (jst *Tracer) GetResult() (json.RawMessage, error) {
   819  	// Transform the context into a JavaScript object and inject into the state
   820  	obj := jst.vm.PushObject()
   821  
   822  	for key, val := range jst.ctx {
   823  		jst.addToObj(obj, key, val)
   824  	}
   825  	jst.vm.PutPropString(jst.stateObject, "ctx")
   826  
   827  	// Finalize the trace and return the results
   828  	result, err := jst.call(false, "result", "ctx", "db")
   829  	if err != nil {
   830  		jst.err = wrapError("result", err)
   831  	}
   832  	// Clean up the JavaScript environment
   833  	jst.vm.DestroyHeap()
   834  	jst.vm.Destroy()
   835  
   836  	return result, jst.err
   837  }
   838  
   839  // addToObj pushes a field to a JS object.
   840  func (jst *Tracer) addToObj(obj int, key string, val interface{}) {
   841  	pushValue(jst.vm, val)
   842  	jst.vm.PutPropString(obj, key)
   843  }
   844  
   845  func pushValue(ctx *duktape.Context, val interface{}) {
   846  	switch val := val.(type) {
   847  	case uint64:
   848  		ctx.PushUint(uint(val))
   849  	case string:
   850  		ctx.PushString(val)
   851  	case []byte:
   852  		ptr := ctx.PushFixedBuffer(len(val))
   853  		copy(makeSlice(ptr, uint(len(val))), val)
   854  	case common.Address:
   855  		ptr := ctx.PushFixedBuffer(20)
   856  		copy(makeSlice(ptr, 20), val[:])
   857  	case *big.Int:
   858  		pushBigInt(val, ctx)
   859  	case int:
   860  		ctx.PushInt(val)
   861  	case uint:
   862  		ctx.PushUint(val)
   863  	case common.Hash:
   864  		ptr := ctx.PushFixedBuffer(32)
   865  		copy(makeSlice(ptr, 32), val[:])
   866  	default:
   867  		panic(fmt.Sprintf("unsupported type: %T", val))
   868  	}
   869  }