mirror of https://github.com/ethereum/go-ethereum
commit
5db3335dce
Binary file not shown.
@ -0,0 +1,20 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/big" |
||||||
|
) |
||||||
|
|
||||||
|
func BigPow(a,b int) *big.Int { |
||||||
|
c := new(big.Int) |
||||||
|
c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0)) |
||||||
|
|
||||||
|
return c |
||||||
|
} |
||||||
|
|
||||||
|
func Big(num string) *big.Int { |
||||||
|
n := new(big.Int) |
||||||
|
n.SetString(num, 0) |
||||||
|
|
||||||
|
return n |
||||||
|
} |
||||||
|
|
@ -0,0 +1,21 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
_"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
type Block struct { |
||||||
|
transactions []*Transaction |
||||||
|
} |
||||||
|
|
||||||
|
func NewBlock(/* TODO use raw data */transactions []*Transaction) *Block { |
||||||
|
block := &Block{ |
||||||
|
// Slice of transactions to include in this block
|
||||||
|
transactions: transactions, |
||||||
|
} |
||||||
|
|
||||||
|
return block |
||||||
|
} |
||||||
|
|
||||||
|
func (block *Block) Update() { |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
|
||||||
|
// Blocks, blocks will have transactions.
|
||||||
|
// Transactions/contracts are updated in goroutines
|
||||||
|
// Each contract should send a message on a channel with usage statistics
|
||||||
|
// The statics can be used for fee calculation within the block update method
|
||||||
|
// Statistics{transaction, /* integers */ normal_ops, store_load, extro_balance, crypto, steps}
|
||||||
|
// The block updater will wait for all goroutines to be finished and update the block accordingly
|
||||||
|
// in one go and should use minimal IO overhead.
|
||||||
|
// The actual block updating will happen within a goroutine as well so normal operation may continue
|
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
_"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
type BlockManager struct { |
||||||
|
vm *Vm |
||||||
|
} |
||||||
|
|
||||||
|
func NewBlockManager() *BlockManager { |
||||||
|
bm := &BlockManager{vm: NewVm()} |
||||||
|
|
||||||
|
return bm |
||||||
|
} |
||||||
|
|
||||||
|
// Process a block.
|
||||||
|
func (bm *BlockManager) ProcessBlock(block *Block) error { |
||||||
|
txCount := len(block.transactions) |
||||||
|
lockChan := make(chan bool, txCount) |
||||||
|
|
||||||
|
for _, tx := range block.transactions { |
||||||
|
go bm.ProcessTransaction(tx, lockChan) |
||||||
|
} |
||||||
|
|
||||||
|
// Wait for all Tx to finish processing
|
||||||
|
for i := 0; i < txCount; i++ { |
||||||
|
<- lockChan |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (bm *BlockManager) ProcessTransaction(tx *Transaction, lockChan chan bool) { |
||||||
|
if tx.recipient == 0x0 { |
||||||
|
bm.vm.RunTransaction(tx, func(opType OpType) bool { |
||||||
|
// TODO calculate fees
|
||||||
|
|
||||||
|
return true // Continue
|
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Broadcast we're done
|
||||||
|
lockChan <- true |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
InitFees() |
||||||
|
|
||||||
|
bm := NewBlockManager() |
||||||
|
|
||||||
|
tx := NewTransaction(0x0, 20, []string{ |
||||||
|
"SET 10 6", |
||||||
|
"LD 10 10", |
||||||
|
"LT 10 1 20", |
||||||
|
"SET 255 7", |
||||||
|
"JMPI 20 255", |
||||||
|
"STOP", |
||||||
|
"SET 30 200", |
||||||
|
"LD 30 31", |
||||||
|
"SET 255 22", |
||||||
|
"JMPI 31 255", |
||||||
|
"SET 255 15", |
||||||
|
"JMP 255", |
||||||
|
}) |
||||||
|
tx2 := NewTransaction(0x0, 20, []string{"SET 10 6", "LD 10 10"}) |
||||||
|
|
||||||
|
blck := NewBlock([]*Transaction{tx2, tx}) |
||||||
|
|
||||||
|
bm.ProcessBlock( blck ) |
||||||
|
|
||||||
|
fmt.Printf("rlp encoded Tx %q\n", tx.Serialize()) |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"strings" |
||||||
|
"errors" |
||||||
|
"math/big" |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
// Op codes
|
||||||
|
var OpCodes = map[string]string{ |
||||||
|
"STOP": "0", |
||||||
|
"ADD": "16", // 0x10
|
||||||
|
"SUB": "17", // 0x11
|
||||||
|
"MUL": "18", // 0x12
|
||||||
|
"DIV": "19", // 0x13
|
||||||
|
"SDIV": "20", // 0x14
|
||||||
|
"MOD": "21", // 0x15
|
||||||
|
"SMOD": "22", // 0x16
|
||||||
|
"EXP": "23", // 0x17
|
||||||
|
"NEG": "24", // 0x18
|
||||||
|
"LT": "32", // 0x20
|
||||||
|
"LE": "33", // 0x21
|
||||||
|
"GT": "34", // 0x22
|
||||||
|
"GE": "35", // 0x23
|
||||||
|
"EQ": "36", // 0x24
|
||||||
|
"NOT": "37", // 0x25
|
||||||
|
"SHA256": "48", // 0x30
|
||||||
|
"RIPEMD160": "49", // 0x31
|
||||||
|
"ECMUL": "50", // 0x32
|
||||||
|
"ECADD": "51", // 0x33
|
||||||
|
"SIGN": "52", // 0x34
|
||||||
|
"RECOVER": "53", // 0x35
|
||||||
|
"COPY": "64", // 0x40
|
||||||
|
"ST": "65", // 0x41
|
||||||
|
"LD": "66", // 0x42
|
||||||
|
"SET": "67", // 0x43
|
||||||
|
"JMP": "80", // 0x50
|
||||||
|
"JMPI": "81", // 0x51
|
||||||
|
"IND": "82", // 0x52
|
||||||
|
"EXTRO": "96", // 0x60
|
||||||
|
"BALANCE": "97", // 0x61
|
||||||
|
"MKTX": "112", // 0x70
|
||||||
|
"DATA": "128", // 0x80
|
||||||
|
"DATAN": "129", // 0x81
|
||||||
|
"MYADDRESS": "144", // 0x90
|
||||||
|
"BLKHASH": "145", // 0x91
|
||||||
|
"COINBASE": "146", // 0x92
|
||||||
|
"SUICIDE": "255", // 0xff
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
func CompileInstr(s string) (string, error) { |
||||||
|
tokens := strings.Split(s, " ") |
||||||
|
if OpCodes[tokens[0]] == "" { |
||||||
|
return "", errors.New(fmt.Sprintf("OP not found: %s", tokens[0])) |
||||||
|
} |
||||||
|
|
||||||
|
code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent
|
||||||
|
op := new(big.Int) |
||||||
|
op.SetString(code, 0) |
||||||
|
|
||||||
|
args := make([]*big.Int, 6) |
||||||
|
for i, val := range tokens[1:len(tokens)] { |
||||||
|
num := new(big.Int) |
||||||
|
num.SetString(val, 0) |
||||||
|
args[i] = num |
||||||
|
} |
||||||
|
|
||||||
|
// Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6
|
||||||
|
base := new(big.Int) |
||||||
|
x := new(big.Int) |
||||||
|
y := new(big.Int) |
||||||
|
z := new(big.Int) |
||||||
|
a := new(big.Int) |
||||||
|
b := new(big.Int) |
||||||
|
c := new(big.Int) |
||||||
|
|
||||||
|
if args[0] != nil { x.Mul(args[0], big.NewInt(256)) } |
||||||
|
if args[1] != nil { y.Mul(args[1], BigPow(256, 2)) } |
||||||
|
if args[2] != nil { z.Mul(args[2], BigPow(256, 3)) } |
||||||
|
if args[3] != nil { a.Mul(args[3], BigPow(256, 4)) } |
||||||
|
if args[4] != nil { b.Mul(args[4], BigPow(256, 5)) } |
||||||
|
if args[5] != nil { c.Mul(args[5], BigPow(256, 6)) } |
||||||
|
|
||||||
|
base.Add(op, x) |
||||||
|
base.Add(base, y) |
||||||
|
base.Add(base, z) |
||||||
|
base.Add(base, a) |
||||||
|
base.Add(base, b) |
||||||
|
base.Add(base, c) |
||||||
|
|
||||||
|
return base.String(), nil |
||||||
|
} |
||||||
|
|
||||||
|
func Instr(instr string) (int, []string, error) { |
||||||
|
base := new(big.Int) |
||||||
|
base.SetString(instr, 0) |
||||||
|
|
||||||
|
args := make([]string, 7) |
||||||
|
for i := 0; i < 7; i++ { |
||||||
|
// int(int(val) / int(math.Pow(256,float64(i)))) % 256
|
||||||
|
exp := BigPow(256, i) |
||||||
|
num := new(big.Int) |
||||||
|
num.Div(base, exp) |
||||||
|
|
||||||
|
args[i] = num.Mod(num, big.NewInt(256)).String() |
||||||
|
} |
||||||
|
op, _ := strconv.Atoi(args[0]) |
||||||
|
|
||||||
|
return op, args[1:7], nil |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
"math" |
||||||
|
) |
||||||
|
|
||||||
|
func TestCompile(t *testing.T) { |
||||||
|
instr, err := CompileInstr("SET 10 1") |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
t.Error("Failed compiling instruction") |
||||||
|
} |
||||||
|
|
||||||
|
calc := (67 + 10 * 256 + 1 * int64(math.Pow(256,2))) |
||||||
|
if Big(instr).Int64() != calc { |
||||||
|
t.Error("Expected", calc, ", got:", instr) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestValidInstr(t *testing.T) { |
||||||
|
op, args, err := Instr("68163") |
||||||
|
if err != nil { |
||||||
|
t.Error("Error decoding instruction") |
||||||
|
} |
||||||
|
|
||||||
|
if op != oSET { |
||||||
|
t.Error("Expected op to be 43, got:", op) |
||||||
|
} |
||||||
|
|
||||||
|
if args[0] != "10" { |
||||||
|
t.Error("Expect args[0] to be 10, got:", args[0]) |
||||||
|
} |
||||||
|
|
||||||
|
if args[1] != "1" { |
||||||
|
t.Error("Expected args[1] to be 1, got:", args[1]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestInvalidInstr(t *testing.T) { |
||||||
|
} |
||||||
|
|
@ -0,0 +1,57 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"math" |
||||||
|
"bytes" |
||||||
|
) |
||||||
|
|
||||||
|
func ToBinary(x int, bytes int) string { |
||||||
|
if bytes == 0 { |
||||||
|
return "" |
||||||
|
} else { |
||||||
|
return ToBinary(int(x / 256), bytes - 1) + string(x % 256) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func NumToVarInt(x int) string { |
||||||
|
if x < 253 { |
||||||
|
return string(x) |
||||||
|
} else if x < int(math.Pow(2,16)) { |
||||||
|
return string(253) + ToBinary(x, 2) |
||||||
|
} else if x < int(math.Pow(2,32)) { |
||||||
|
return string(253) + ToBinary(x, 4) |
||||||
|
} else { |
||||||
|
return string(253) + ToBinary(x, 8) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func RlpEncode(object interface{}) string { |
||||||
|
if str, ok := object.(string); ok { |
||||||
|
return "\x00" + NumToVarInt(len(str)) + str |
||||||
|
} else if slice, ok := object.([]interface{}); ok { |
||||||
|
var buffer bytes.Buffer |
||||||
|
for _, val := range slice { |
||||||
|
if v, ok := val.(string); ok { |
||||||
|
buffer.WriteString(RlpEncode(v)) |
||||||
|
} else { |
||||||
|
buffer.WriteString(RlpEncode(val)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return "\x01" + RlpEncode(len(buffer.String())) + buffer.String() |
||||||
|
} else if slice, ok := object.([]string); ok { |
||||||
|
|
||||||
|
// FIXME this isn't dry. Fix this
|
||||||
|
var buffer bytes.Buffer |
||||||
|
for _, val := range slice { |
||||||
|
buffer.WriteString(RlpEncode(val)) |
||||||
|
} |
||||||
|
return "\x01" + RlpEncode(len(buffer.String())) + buffer.String() |
||||||
|
} |
||||||
|
|
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
type RlpSerializer interface { |
||||||
|
} |
||||||
|
|
@ -0,0 +1,20 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
func TestRlpEncode(t *testing.T) { |
||||||
|
strRes := "\x00\x03dog" |
||||||
|
str := RlpEncode("dog") |
||||||
|
if str != strRes { |
||||||
|
t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) |
||||||
|
} |
||||||
|
|
||||||
|
sliceRes := "\x01\x00\x03dog\x00\x03god\x00\x03cat" |
||||||
|
slice := RlpEncode([]string{"dog", "god", "cat"}) |
||||||
|
if slice != sliceRes { |
||||||
|
t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/big" |
||||||
|
"fmt" |
||||||
|
"encoding/hex" |
||||||
|
"crypto/sha256" |
||||||
|
_ "bytes" |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
/* |
||||||
|
Transaction Contract Size |
||||||
|
------------------------------------------- |
||||||
|
sender sender 20 bytes |
||||||
|
recipient 0x0 20 bytes |
||||||
|
value endowment 4 bytes (uint32) |
||||||
|
fee fee 4 bytes (uint32) |
||||||
|
d_size o_size 4 bytes (uint32) |
||||||
|
data ops * |
||||||
|
signature signature 64 bytes |
||||||
|
*/ |
||||||
|
|
||||||
|
var StepFee *big.Int = new(big.Int) |
||||||
|
var TxFee *big.Int = new(big.Int) |
||||||
|
var MemFee *big.Int = new(big.Int) |
||||||
|
var DataFee *big.Int = new(big.Int) |
||||||
|
var CryptoFee *big.Int = new(big.Int) |
||||||
|
var ExtroFee *big.Int = new(big.Int) |
||||||
|
|
||||||
|
var Period1Reward *big.Int = new(big.Int) |
||||||
|
var Period2Reward *big.Int = new(big.Int) |
||||||
|
var Period3Reward *big.Int = new(big.Int) |
||||||
|
var Period4Reward *big.Int = new(big.Int) |
||||||
|
|
||||||
|
type Transaction struct { |
||||||
|
sender string |
||||||
|
recipient uint32 |
||||||
|
value uint32 |
||||||
|
fee uint32 |
||||||
|
data []string |
||||||
|
memory []int |
||||||
|
signature string |
||||||
|
|
||||||
|
addr string |
||||||
|
} |
||||||
|
|
||||||
|
func NewTransaction(to uint32, value uint32, data []string) *Transaction { |
||||||
|
tx := Transaction{sender: "1234567890", recipient: to, value: value} |
||||||
|
tx.fee = 0//uint32((ContractFee + MemoryFee * float32(len(tx.data))) * 1e8)
|
||||||
|
|
||||||
|
// Serialize the data
|
||||||
|
tx.data = make([]string, len(data)) |
||||||
|
for i, val := range data { |
||||||
|
instr, err := CompileInstr(val) |
||||||
|
if err != nil { |
||||||
|
fmt.Printf("compile error:%d %v", i+1, err) |
||||||
|
} |
||||||
|
|
||||||
|
tx.data[i] = instr |
||||||
|
} |
||||||
|
|
||||||
|
b:= []byte(tx.Serialize()) |
||||||
|
hash := sha256.Sum256(b) |
||||||
|
tx.addr = hex.EncodeToString(hash[0:19]) |
||||||
|
|
||||||
|
return &tx |
||||||
|
} |
||||||
|
|
||||||
|
func Uitoa(i uint32) string { |
||||||
|
return strconv.FormatUint(uint64(i), 10) |
||||||
|
} |
||||||
|
|
||||||
|
func (tx *Transaction) Serialize() string { |
||||||
|
// Prepare the transaction for serialization
|
||||||
|
preEnc := []interface{}{ |
||||||
|
"0", // TODO last Tx
|
||||||
|
tx.sender, |
||||||
|
// XXX In the future there's no need to cast to string because they'll end up being big numbers (strings)
|
||||||
|
Uitoa(tx.recipient), |
||||||
|
Uitoa(tx.value), |
||||||
|
Uitoa(tx.fee), |
||||||
|
tx.data, |
||||||
|
} |
||||||
|
|
||||||
|
return RlpEncode(preEnc) |
||||||
|
} |
||||||
|
|
||||||
|
func InitFees() { |
||||||
|
// Base for 2**60
|
||||||
|
b60 := new(big.Int) |
||||||
|
b60.Exp(big.NewInt(2), big.NewInt(60), big.NewInt(0)) |
||||||
|
// Base for 2**80
|
||||||
|
b80 := new(big.Int) |
||||||
|
b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0)) |
||||||
|
|
||||||
|
StepFee.Mul(b60, big.NewInt(4096)) |
||||||
|
//fmt.Println("StepFee:", StepFee)
|
||||||
|
|
||||||
|
TxFee.Mul(b60, big.NewInt(524288)) |
||||||
|
//fmt.Println("TxFee:", TxFee)
|
||||||
|
|
||||||
|
MemFee.Mul(b60, big.NewInt(262144)) |
||||||
|
//fmt.Println("MemFee:", MemFee)
|
||||||
|
|
||||||
|
DataFee.Mul(b60, big.NewInt(16384)) |
||||||
|
//fmt.Println("DataFee:", DataFee)
|
||||||
|
|
||||||
|
CryptoFee.Mul(b60, big.NewInt(65536)) |
||||||
|
//fmt.Println("CrytoFee:", CryptoFee)
|
||||||
|
|
||||||
|
ExtroFee.Mul(b60, big.NewInt(65536)) |
||||||
|
//fmt.Println("ExtroFee:", ExtroFee)
|
||||||
|
|
||||||
|
Period1Reward.Mul(b80, big.NewInt(1024)) |
||||||
|
//fmt.Println("Period1Reward:", Period1Reward)
|
||||||
|
|
||||||
|
Period2Reward.Mul(b80, big.NewInt(512)) |
||||||
|
//fmt.Println("Period2Reward:", Period2Reward)
|
||||||
|
|
||||||
|
Period3Reward.Mul(b80, big.NewInt(256)) |
||||||
|
//fmt.Println("Period3Reward:", Period3Reward)
|
||||||
|
|
||||||
|
Period4Reward.Mul(b80, big.NewInt(128)) |
||||||
|
//fmt.Println("Period4Reward:", Period4Reward)
|
||||||
|
} |
@ -0,0 +1,182 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"math" |
||||||
|
"math/big" |
||||||
|
"fmt" |
||||||
|
"strconv" |
||||||
|
_ "encoding/hex" |
||||||
|
) |
||||||
|
|
||||||
|
// Op codes
|
||||||
|
const ( |
||||||
|
oSTOP int = 0x00 |
||||||
|
oADD int = 0x10 |
||||||
|
oSUB int = 0x11 |
||||||
|
oMUL int = 0x12 |
||||||
|
oDIV int = 0x13 |
||||||
|
oSDIV int = 0x14 |
||||||
|
oMOD int = 0x15 |
||||||
|
oSMOD int = 0x16 |
||||||
|
oEXP int = 0x17 |
||||||
|
oNEG int = 0x18 |
||||||
|
oLT int = 0x20 |
||||||
|
oLE int = 0x21 |
||||||
|
oGT int = 0x22 |
||||||
|
oGE int = 0x23 |
||||||
|
oEQ int = 0x24 |
||||||
|
oNOT int = 0x25 |
||||||
|
oSHA256 int = 0x30 |
||||||
|
oRIPEMD160 int = 0x31 |
||||||
|
oECMUL int = 0x32 |
||||||
|
oECADD int = 0x33 |
||||||
|
oSIGN int = 0x34 |
||||||
|
oRECOVER int = 0x35 |
||||||
|
oCOPY int = 0x40 |
||||||
|
oST int = 0x41 |
||||||
|
oLD int = 0x42 |
||||||
|
oSET int = 0x43 |
||||||
|
oJMP int = 0x50 |
||||||
|
oJMPI int = 0x51 |
||||||
|
oIND int = 0x52 |
||||||
|
oEXTRO int = 0x60 |
||||||
|
oBALANCE int = 0x61 |
||||||
|
oMKTX int = 0x70 |
||||||
|
oDATA int = 0x80 |
||||||
|
oDATAN int = 0x81 |
||||||
|
oMYADDRESS int = 0x90 |
||||||
|
oSUICIDE int = 0xff |
||||||
|
) |
||||||
|
|
||||||
|
type OpType int |
||||||
|
const ( |
||||||
|
tNorm = iota |
||||||
|
tData |
||||||
|
tExtro |
||||||
|
tCrypto |
||||||
|
) |
||||||
|
type TxCallback func(opType OpType) bool |
||||||
|
|
||||||
|
type Vm struct { |
||||||
|
// Memory stack
|
||||||
|
stack map[string]string |
||||||
|
// Index ptr
|
||||||
|
iptr int |
||||||
|
memory map[string]map[string]string |
||||||
|
} |
||||||
|
|
||||||
|
func NewVm() *Vm { |
||||||
|
fmt.Println("init Ethereum VM") |
||||||
|
|
||||||
|
stackSize := uint(256) |
||||||
|
fmt.Println("stack size =", stackSize) |
||||||
|
|
||||||
|
return &Vm{make(map[string]string), 0, make(map[string]map[string]string)} |
||||||
|
} |
||||||
|
|
||||||
|
func (vm *Vm) RunTransaction(tx *Transaction, cb TxCallback) { |
||||||
|
fmt.Printf(` |
||||||
|
# processing Tx (%v) |
||||||
|
# fee = %f, ops = %d, sender = %s, value = %d |
||||||
|
`, tx.addr, float32(tx.fee) / 1e8, len(tx.data), tx.sender, tx.value) |
||||||
|
|
||||||
|
vm.stack = make(map[string]string) |
||||||
|
vm.stack["0"] = tx.sender |
||||||
|
vm.stack["1"] = "100" //int(tx.value)
|
||||||
|
vm.stack["1"] = "1000" //int(tx.fee)
|
||||||
|
|
||||||
|
//vm.memory[tx.addr] = make([]int, 256)
|
||||||
|
vm.memory[tx.addr] = make(map[string]string) |
||||||
|
|
||||||
|
// Define instruction 'accessors' for the instruction, which makes it more readable
|
||||||
|
// also called register values, shorthanded as Rx/y/z. Memory address are shorthanded as Mx/y/z.
|
||||||
|
// Instructions are shorthanded as Ix/y/z
|
||||||
|
x := 0; y := 1; z := 2; //a := 3; b := 4; c := 5
|
||||||
|
out: |
||||||
|
for vm.iptr < len(tx.data) { |
||||||
|
// The base big int for all calculations. Use this for any results.
|
||||||
|
base := new(big.Int) |
||||||
|
// XXX Should Instr return big int slice instead of string slice?
|
||||||
|
op, args, _ := Instr(tx.data[vm.iptr]) |
||||||
|
|
||||||
|
fmt.Printf("%-3d %d %v\n", vm.iptr, op, args) |
||||||
|
|
||||||
|
opType := OpType(tNorm) |
||||||
|
// Determine the op type (used for calculating fees by the block manager)
|
||||||
|
switch op { |
||||||
|
case oEXTRO, oBALANCE: |
||||||
|
opType = tExtro |
||||||
|
case oSHA256, oRIPEMD160, oECMUL, oECADD: // TODO add rest
|
||||||
|
opType = tCrypto |
||||||
|
} |
||||||
|
|
||||||
|
// If the callback yielded a negative result abort execution
|
||||||
|
if !cb(opType) { break out } |
||||||
|
|
||||||
|
nptr := vm.iptr |
||||||
|
switch op { |
||||||
|
case oSTOP: |
||||||
|
fmt.Println("exiting (oSTOP), idx =", nptr) |
||||||
|
|
||||||
|
break out |
||||||
|
case oADD: |
||||||
|
// (Rx + Ry) % 2 ** 256
|
||||||
|
base.Add(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]])) |
||||||
|
base.Mod(base, big.NewInt(int64(math.Pow(2, 256)))) |
||||||
|
// Set the result to Rz
|
||||||
|
vm.stack[args[ z ]] = base.String() |
||||||
|
case oSUB: |
||||||
|
// (Rx - Ry) % 2 ** 256
|
||||||
|
base.Sub(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]])) |
||||||
|
base.Mod(base, big.NewInt(int64(math.Pow(2, 256)))) |
||||||
|
// Set the result to Rz
|
||||||
|
vm.stack[args[ z ]] = base.String() |
||||||
|
case oMUL: |
||||||
|
// (Rx * Ry) % 2 ** 256
|
||||||
|
base.Mul(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]])) |
||||||
|
base.Mod(base, big.NewInt(int64(math.Pow(2, 256)))) |
||||||
|
// Set the result to Rz
|
||||||
|
vm.stack[args[ z ]] = base.String() |
||||||
|
case oDIV: |
||||||
|
// floor(Rx / Ry)
|
||||||
|
base.Div(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]])) |
||||||
|
// Set the result to Rz
|
||||||
|
vm.stack[args[ z ]] = base.String() |
||||||
|
case oSET: |
||||||
|
// Set the (numeric) value at Iy to Rx
|
||||||
|
vm.stack[args[ x ]] = args[ y ] |
||||||
|
case oLD: |
||||||
|
// Load the value at Mx to Ry
|
||||||
|
vm.stack[args[ y ]] = vm.memory[tx.addr][vm.stack[args[ x ]]] |
||||||
|
case oLT: |
||||||
|
cmp := Big(vm.stack[args[ x ]]).Cmp( Big(vm.stack[args[ y ]]) ) |
||||||
|
// Set the result as "boolean" value to Rz
|
||||||
|
if cmp < 0 { // a < b
|
||||||
|
vm.stack[args[ z ]] = "1" |
||||||
|
} else { |
||||||
|
vm.stack[args[ z ]] = "0" |
||||||
|
} |
||||||
|
case oJMP: |
||||||
|
// Set the instruction pointer to the value at Rx
|
||||||
|
ptr, _ := strconv.Atoi( vm.stack[args[ x ]] ) |
||||||
|
nptr = ptr |
||||||
|
case oJMPI: |
||||||
|
// Set the instruction pointer to the value at Ry if Rx yields true
|
||||||
|
if vm.stack[args[ x ]] != "0" { |
||||||
|
ptr, _ := strconv.Atoi( vm.stack[args[ y ]] ) |
||||||
|
nptr = ptr |
||||||
|
} |
||||||
|
default: |
||||||
|
fmt.Println("Error op", op) |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
if vm.iptr == nptr { |
||||||
|
vm.iptr++ |
||||||
|
} else { |
||||||
|
vm.iptr = nptr |
||||||
|
fmt.Println("... JMP", nptr, "...") |
||||||
|
} |
||||||
|
} |
||||||
|
fmt.Println("# finished processing Tx\n") |
||||||
|
} |
Loading…
Reference in new issue