mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 05:36:46 +00:00
core/vm: native functions
This commit is contained in:
parent
27bf7b6c65
commit
f17ae6b256
3 changed files with 344 additions and 93 deletions
|
|
@ -129,6 +129,7 @@ func run(ctx *cli.Context) {
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
|
if !vm.DisableSegmentation {
|
||||||
vmstart = time.Now()
|
vmstart = time.Now()
|
||||||
ret, e = vmenv.Call(
|
ret, e = vmenv.Call(
|
||||||
sender,
|
sender,
|
||||||
|
|
@ -144,6 +145,7 @@ func run(ctx *cli.Context) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
fmt.Println("with segmentation", time.Since(vmstart))
|
fmt.Println("with segmentation", time.Since(vmstart))
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.GlobalBool(DumpFlag.Name) {
|
if ctx.GlobalBool(DumpFlag.Name) {
|
||||||
fmt.Println(string(statedb.Dump()))
|
fmt.Println(string(statedb.Dump()))
|
||||||
|
|
|
||||||
283
core/vm/native.go
Normal file
283
core/vm/native.go
Normal file
|
|
@ -0,0 +1,283 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/hashicorp/golang-lru"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
segments *lru.Cache
|
||||||
|
DisableSegmentation bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
segments, _ = lru.New(256)
|
||||||
|
}
|
||||||
|
|
||||||
|
type codeSegments map[uint64]*segment
|
||||||
|
|
||||||
|
// operation is a "native" implementation of an OpCode
|
||||||
|
type operation struct {
|
||||||
|
fn func(*stack, []byte)
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type segment struct {
|
||||||
|
cstart, cend, next uint64
|
||||||
|
msize uint64
|
||||||
|
gas *big.Int
|
||||||
|
|
||||||
|
ssize int
|
||||||
|
|
||||||
|
ops []operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *segment) String() string {
|
||||||
|
return fmt.Sprintf("{%d %d %d %v}", c.cstart, c.cend, c.msize, c.gas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// native operations
|
||||||
|
|
||||||
|
func opPush(s *stack, data []byte) {
|
||||||
|
s.push(common.BytesToBig(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opAdd(s *stack, data []byte) {
|
||||||
|
s.push(U256(new(big.Int).Add(s.pop(), s.pop())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSub(s *stack, data []byte) {
|
||||||
|
s.push(U256(new(big.Int).Sub(s.pop(), s.pop())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opMul(s *stack, data []byte) {
|
||||||
|
s.push(U256(new(big.Int).Mul(s.pop(), s.pop())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opDiv(s *stack, data []byte) {
|
||||||
|
x, y := s.pop(), s.pop()
|
||||||
|
|
||||||
|
if y.Cmp(common.Big0) != 0 {
|
||||||
|
new(big.Int).Div(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
U256(new(big.Int))
|
||||||
|
|
||||||
|
// pop result back on the s
|
||||||
|
s.push(new(big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSdiv(s *stack, data []byte) {
|
||||||
|
x, y := S256(s.pop()), S256(s.pop())
|
||||||
|
|
||||||
|
if y.Cmp(common.Big0) == 0 {
|
||||||
|
new(big.Int).Set(common.Big0)
|
||||||
|
} else {
|
||||||
|
n := new(big.Int)
|
||||||
|
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
|
||||||
|
n.SetInt64(-1)
|
||||||
|
} else {
|
||||||
|
n.SetInt64(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
new(big.Int).Div(x.Abs(x), y.Abs(y)).Mul(new(big.Int), n)
|
||||||
|
|
||||||
|
U256(new(big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push(new(big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opMod(s *stack, data []byte) {
|
||||||
|
x, y := s.pop(), s.pop()
|
||||||
|
|
||||||
|
if y.Cmp(common.Big0) == 0 {
|
||||||
|
new(big.Int).Set(common.Big0)
|
||||||
|
} else {
|
||||||
|
new(big.Int).Mod(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
U256(new(big.Int))
|
||||||
|
|
||||||
|
s.push(new(big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSmod(s *stack, data []byte) {
|
||||||
|
x, y := S256(s.pop()), S256(s.pop())
|
||||||
|
|
||||||
|
if y.Cmp(common.Big0) == 0 {
|
||||||
|
new(big.Int).Set(common.Big0)
|
||||||
|
} else {
|
||||||
|
n := new(big.Int)
|
||||||
|
if x.Cmp(common.Big0) < 0 {
|
||||||
|
n.SetInt64(-1)
|
||||||
|
} else {
|
||||||
|
n.SetInt64(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
new(big.Int).Mod(x.Abs(x), y.Abs(y)).Mul(new(big.Int), n)
|
||||||
|
|
||||||
|
U256(new(big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push(new(big.Int))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func opExp(s *stack, data []byte) {
|
||||||
|
x, y := s.pop(), s.pop()
|
||||||
|
|
||||||
|
new(big.Int).Exp(x, y, Pow256)
|
||||||
|
|
||||||
|
U256(new(big.Int))
|
||||||
|
|
||||||
|
s.push(new(big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSignextend(s *stack, data []byte) {
|
||||||
|
back := s.pop()
|
||||||
|
if back.Cmp(big.NewInt(31)) < 0 {
|
||||||
|
bit := uint(back.Uint64()*8 + 7)
|
||||||
|
num := s.pop()
|
||||||
|
mask := new(big.Int).Lsh(common.Big1, bit)
|
||||||
|
mask.Sub(mask, common.Big1)
|
||||||
|
if common.BitTest(num, int(bit)) {
|
||||||
|
num.Or(num, mask.Not(mask))
|
||||||
|
} else {
|
||||||
|
num.And(num, mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
num = U256(num)
|
||||||
|
|
||||||
|
s.push(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opNot(s *stack, data []byte) {
|
||||||
|
s.push(U256(new(big.Int).Not(s.pop())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opLt(s *stack, data []byte) {
|
||||||
|
x, y := s.pop(), s.pop()
|
||||||
|
|
||||||
|
// x < y
|
||||||
|
if x.Cmp(y) < 0 {
|
||||||
|
s.push(common.BigTrue)
|
||||||
|
} else {
|
||||||
|
s.push(common.BigFalse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opGt(s *stack, data []byte) {
|
||||||
|
x, y := s.pop(), s.pop()
|
||||||
|
|
||||||
|
// x > y
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
s.push(common.BigTrue)
|
||||||
|
} else {
|
||||||
|
s.push(common.BigFalse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSlt(s *stack, data []byte) {
|
||||||
|
x, y := S256(s.pop()), S256(s.pop())
|
||||||
|
|
||||||
|
// x < y
|
||||||
|
if x.Cmp(S256(y)) < 0 {
|
||||||
|
s.push(common.BigTrue)
|
||||||
|
} else {
|
||||||
|
s.push(common.BigFalse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSgt(s *stack, data []byte) {
|
||||||
|
x, y := S256(s.pop()), S256(s.pop())
|
||||||
|
|
||||||
|
// x > y
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
s.push(common.BigTrue)
|
||||||
|
} else {
|
||||||
|
s.push(common.BigFalse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opEq(s *stack, data []byte) {
|
||||||
|
x, y := s.pop(), s.pop()
|
||||||
|
|
||||||
|
// x == y
|
||||||
|
if x.Cmp(y) == 0 {
|
||||||
|
s.push(common.BigTrue)
|
||||||
|
} else {
|
||||||
|
s.push(common.BigFalse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opIszero(s *stack, data []byte) {
|
||||||
|
x := s.pop()
|
||||||
|
if x.Cmp(common.BigFalse) > 0 {
|
||||||
|
s.push(common.BigFalse)
|
||||||
|
} else {
|
||||||
|
s.push(common.BigTrue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opAnd(s *stack, data []byte) {
|
||||||
|
s.push(new(big.Int).And(s.pop(), s.pop()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opOr(s *stack, data []byte) {
|
||||||
|
s.push(new(big.Int).Or(s.pop(), s.pop()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opXor(s *stack, data []byte) {
|
||||||
|
s.push(new(big.Int).Xor(s.pop(), s.pop()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opByte(s *stack, data []byte) {
|
||||||
|
th, val := s.pop(), s.pop()
|
||||||
|
|
||||||
|
res := new(big.Int)
|
||||||
|
if th.Cmp(big.NewInt(32)) < 0 {
|
||||||
|
byt := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
||||||
|
|
||||||
|
res.Set(byt)
|
||||||
|
} else {
|
||||||
|
res.Set(common.BigFalse)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func opAddmod(s *stack, data []byte) {
|
||||||
|
x := s.pop()
|
||||||
|
y := s.pop()
|
||||||
|
z := s.pop()
|
||||||
|
|
||||||
|
res := new(big.Int)
|
||||||
|
if z.Cmp(Zero) > 0 {
|
||||||
|
add := new(big.Int).Add(x, y)
|
||||||
|
res.Mod(add, z)
|
||||||
|
res = U256(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func opMulmod(s *stack, data []byte) {
|
||||||
|
x := s.pop()
|
||||||
|
y := s.pop()
|
||||||
|
z := s.pop()
|
||||||
|
|
||||||
|
res := new(big.Int)
|
||||||
|
if z.Cmp(Zero) > 0 {
|
||||||
|
res.Mul(x, y)
|
||||||
|
res.Mod(res, z)
|
||||||
|
|
||||||
|
res = U256(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push(res)
|
||||||
|
}
|
||||||
|
|
@ -9,46 +9,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type operation struct {
|
|
||||||
fn func(*stack, []byte)
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func Add(s *stack, data []byte) {
|
|
||||||
s.push(new(big.Int).Add(s.pop(), s.pop()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Push(s *stack, data []byte) {
|
|
||||||
s.push(common.BytesToBig(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
type codeSegments map[uint64]*segment
|
|
||||||
|
|
||||||
var segments *lru.Cache
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
segments, _ = lru.New(256)
|
|
||||||
}
|
|
||||||
|
|
||||||
var DisableSegmentation bool
|
|
||||||
|
|
||||||
type segment struct {
|
|
||||||
cstart, cend, next uint64
|
|
||||||
msize uint64
|
|
||||||
gas *big.Int
|
|
||||||
|
|
||||||
ssize int
|
|
||||||
|
|
||||||
ops []operation
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *segment) String() string {
|
|
||||||
return fmt.Sprintf("{%d %d %d %v}", c.cstart, c.cend, c.msize, c.gas)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vm implements VirtualMachine
|
// Vm implements VirtualMachine
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
env Environment
|
env Environment
|
||||||
|
|
@ -164,7 +126,8 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||||
for {
|
for {
|
||||||
// Get the current operation location of pc
|
// Get the current operation location of pc
|
||||||
op = context.GetOp(pc)
|
op = context.GetOp(pc)
|
||||||
if isDynamic(op) && csegment != nil && !DisableSegmentation {
|
if !DisableSegmentation {
|
||||||
|
if isDynamic(op) && csegment != nil {
|
||||||
// end of segment bound
|
// end of segment bound
|
||||||
csegment.cend = ppc
|
csegment.cend = ppc
|
||||||
csegment.next = pc
|
csegment.next = pc
|
||||||
|
|
@ -179,7 +142,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||||
csegment.ssize = int(math.Abs(math.Min(float64(stack.len()-csegment.ssize), 0)))
|
csegment.ssize = int(math.Abs(math.Min(float64(stack.len()-csegment.ssize), 0)))
|
||||||
csegment = nil
|
csegment = nil
|
||||||
nopay = 0
|
nopay = 0
|
||||||
} else if csegment == nil && pc != 0 && !DisableSegmentation {
|
} else if csegment == nil && pc != 0 {
|
||||||
// check if a segment is available to us and set it.
|
// check if a segment is available to us and set it.
|
||||||
if seg, ok := csegments[pc]; ok {
|
if seg, ok := csegments[pc]; ok {
|
||||||
nopay = seg.cend
|
nopay = seg.cend
|
||||||
|
|
@ -208,6 +171,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||||
csegments[pc] = csegment
|
csegments[pc] = csegment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if pc > nopay || pc == 0 || DisableSegmentation {
|
if pc > nopay || pc == 0 || DisableSegmentation {
|
||||||
// calculate the new memory size and gas price for the current executing opcode
|
// calculate the new memory size and gas price for the current executing opcode
|
||||||
|
|
@ -247,7 +211,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
addop(operation{Add, nil})
|
addop(operation{opAdd, nil})
|
||||||
|
|
||||||
// pop result back on the stack
|
// pop result back on the stack
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
|
|
@ -339,6 +303,8 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
|
|
||||||
|
addop(operation{opExp, nil})
|
||||||
case SIGNEXTEND:
|
case SIGNEXTEND:
|
||||||
back := stack.pop()
|
back := stack.pop()
|
||||||
if back.Cmp(big.NewInt(31)) < 0 {
|
if back.Cmp(big.NewInt(31)) < 0 {
|
||||||
|
|
@ -582,7 +548,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||||
size := uint64(op - PUSH1 + 1)
|
size := uint64(op - PUSH1 + 1)
|
||||||
byts := getData(code, new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
|
byts := getData(code, new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
|
||||||
|
|
||||||
addop(operation{Push, byts})
|
addop(operation{opPush, byts})
|
||||||
|
|
||||||
// push value to stack
|
// push value to stack
|
||||||
stack.push(common.Bytes2Big(byts))
|
stack.push(common.Bytes2Big(byts))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue