Moving the ethgo to individual packages
This commit is contained in:
parent
f6fa4f8879
commit
8bbf879cb3
35
big.go
35
big.go
@ -1,35 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the power of two integers
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Like big.NewInt(uint64); this takes a string instead.
|
|
||||||
*/
|
|
||||||
func Big(num string) *big.Int {
|
|
||||||
n := new(big.Int)
|
|
||||||
n.SetString(num, 0)
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Like big.NewInt(uint64); this takes a byte buffer instead.
|
|
||||||
*/
|
|
||||||
func BigD(data []byte) *big.Int {
|
|
||||||
n := new(big.Int)
|
|
||||||
n.SetBytes(data)
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
192
block.go
192
block.go
@ -1,192 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
_"bytes"
|
|
||||||
_"encoding/hex"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Block struct {
|
|
||||||
// The number of this block
|
|
||||||
number uint32
|
|
||||||
// Hash to the previous block
|
|
||||||
prevHash string
|
|
||||||
// Uncles of this block
|
|
||||||
uncles []*Block
|
|
||||||
coinbase string
|
|
||||||
// state xxx
|
|
||||||
state *Trie
|
|
||||||
difficulty uint32
|
|
||||||
// Creation time
|
|
||||||
time int64
|
|
||||||
nonce uint32
|
|
||||||
// List of transactions and/or contracts
|
|
||||||
transactions []*Transaction
|
|
||||||
|
|
||||||
extra string
|
|
||||||
}
|
|
||||||
|
|
||||||
// New block takes a raw encoded string
|
|
||||||
func NewBlock(raw []byte) *Block {
|
|
||||||
block := &Block{}
|
|
||||||
block.UnmarshalRlp(raw)
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new block. This is currently for testing
|
|
||||||
func CreateTestBlock(/* TODO use raw data */transactions []*Transaction) *Block {
|
|
||||||
block := &Block{
|
|
||||||
// Slice of transactions to include in this block
|
|
||||||
transactions: transactions,
|
|
||||||
number: 1,
|
|
||||||
prevHash: "1234",
|
|
||||||
coinbase: "me",
|
|
||||||
difficulty: 10,
|
|
||||||
nonce: 0,
|
|
||||||
time: time.Now().Unix(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateBlock(root string,
|
|
||||||
num int,
|
|
||||||
prevHash string,
|
|
||||||
base string,
|
|
||||||
difficulty int,
|
|
||||||
nonce int,
|
|
||||||
extra string,
|
|
||||||
txes []*Transaction) *Block {
|
|
||||||
|
|
||||||
block := &Block{
|
|
||||||
// Slice of transactions to include in this block
|
|
||||||
transactions: txes,
|
|
||||||
number: uint32(num),
|
|
||||||
prevHash: prevHash,
|
|
||||||
coinbase: base,
|
|
||||||
difficulty: uint32(difficulty),
|
|
||||||
nonce: uint32(nonce),
|
|
||||||
time: time.Now().Unix(),
|
|
||||||
extra: extra,
|
|
||||||
}
|
|
||||||
block.state = NewTrie(Db, root)
|
|
||||||
|
|
||||||
for _, tx := range txes {
|
|
||||||
// Create contract if there's no recipient
|
|
||||||
if tx.recipient == "" {
|
|
||||||
addr := tx.Hash()
|
|
||||||
|
|
||||||
contract := NewContract(tx.value, []byte(""))
|
|
||||||
block.state.Update(string(addr), string(contract.MarshalRlp()))
|
|
||||||
for i, val := range tx.data {
|
|
||||||
contract.state.Update(string(NumberToBytes(uint64(i), 32)), val)
|
|
||||||
}
|
|
||||||
block.UpdateContract(addr, contract)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) GetContract(addr []byte) *Contract {
|
|
||||||
data := block.state.Get(string(addr))
|
|
||||||
if data == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
contract := &Contract{}
|
|
||||||
contract.UnmarshalRlp([]byte(data))
|
|
||||||
|
|
||||||
return contract
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) UpdateContract(addr []byte, contract *Contract) {
|
|
||||||
block.state.Update(string(addr), string(contract.MarshalRlp()))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (block *Block) PayFee(addr []byte, fee uint64) bool {
|
|
||||||
contract := block.GetContract(addr)
|
|
||||||
// If we can't pay the fee return
|
|
||||||
if contract == nil || contract.amount < fee {
|
|
||||||
fmt.Println("Contract has insufficient funds", contract.amount, fee)
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
contract.amount -= fee
|
|
||||||
block.state.Update(string(addr), string(contract.MarshalRlp()))
|
|
||||||
|
|
||||||
data := block.state.Get(string(block.coinbase))
|
|
||||||
|
|
||||||
// Get the ether (coinbase) and add the fee (gief fee to miner)
|
|
||||||
ether := NewEtherFromData([]byte(data))
|
|
||||||
ether.amount += fee
|
|
||||||
|
|
||||||
block.state.Update(string(block.coinbase), string(ether.MarshalRlp()))
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a hash of the block
|
|
||||||
func (block *Block) Hash() []byte {
|
|
||||||
return Sha256Bin(block.MarshalRlp())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) MarshalRlp() []byte {
|
|
||||||
// Marshal the transactions of this block
|
|
||||||
encTx := make([]string, len(block.transactions))
|
|
||||||
for i, tx := range block.transactions {
|
|
||||||
// Cast it to a string (safe)
|
|
||||||
encTx[i] = string(tx.MarshalRlp())
|
|
||||||
}
|
|
||||||
// TODO
|
|
||||||
uncles := []interface{}{}
|
|
||||||
|
|
||||||
// I made up the block. It should probably contain different data or types.
|
|
||||||
// It sole purpose now is testing
|
|
||||||
header := []interface{}{
|
|
||||||
block.number,
|
|
||||||
block.prevHash,
|
|
||||||
// Sha of uncles
|
|
||||||
"",
|
|
||||||
block.coinbase,
|
|
||||||
// root state
|
|
||||||
block.state.root,
|
|
||||||
// Sha of tx
|
|
||||||
string(Sha256Bin([]byte(Encode(encTx)))),
|
|
||||||
block.difficulty,
|
|
||||||
uint64(block.time),
|
|
||||||
block.nonce,
|
|
||||||
block.extra,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode a slice interface which contains the header and the list of
|
|
||||||
// transactions.
|
|
||||||
return Encode([]interface{}{header, encTx, uncles})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (block *Block) UnmarshalRlp(data []byte) {
|
|
||||||
decoder := NewRlpDecoder(data)
|
|
||||||
|
|
||||||
header := decoder.Get(0)
|
|
||||||
block.number = uint32(header.Get(0).AsUint())
|
|
||||||
block.prevHash = header.Get(1).AsString()
|
|
||||||
// sha of uncles is header[2]
|
|
||||||
block.coinbase = header.Get(3).AsString()
|
|
||||||
block.state = NewTrie(Db, header.Get(4).AsString())
|
|
||||||
block.difficulty = uint32(header.Get(5).AsUint())
|
|
||||||
block.time = int64(header.Get(6).AsUint())
|
|
||||||
block.nonce = uint32(header.Get(7).AsUint())
|
|
||||||
block.extra = header.Get(8).AsString()
|
|
||||||
|
|
||||||
txes := decoder.Get(1)
|
|
||||||
block.transactions = make([]*Transaction, txes.Length())
|
|
||||||
for i := 0; i < txes.Length(); i++ {
|
|
||||||
tx := &Transaction{}
|
|
||||||
tx.UnmarshalRlp(txes.Get(i).AsBytes())
|
|
||||||
block.transactions[i] = tx
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,17 +2,18 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockChain struct {
|
type BlockChain struct {
|
||||||
lastBlock *Block
|
lastBlock *ethutil.Block
|
||||||
|
|
||||||
genesisBlock *Block
|
genesisBlock *ethutil.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockChain() *BlockChain {
|
func NewBlockChain() *BlockChain {
|
||||||
bc := &BlockChain{}
|
bc := &BlockChain{}
|
||||||
bc.genesisBlock = NewBlock( Encode(Genesis) )
|
bc.genesisBlock = ethutil.NewBlock( ethutil.Encode(ethutil.Genesis) )
|
||||||
|
|
||||||
return bc
|
return bc
|
||||||
}
|
}
|
||||||
@ -30,19 +31,19 @@ func NewBlockManager() *BlockManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process a block.
|
// Process a block.
|
||||||
func (bm *BlockManager) ProcessBlock(block *Block) error {
|
func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error {
|
||||||
// TODO Validation (Or move to other part of the application)
|
// TODO Validation (Or move to other part of the application)
|
||||||
if err := bm.ValidateBlock(block); err != nil {
|
if err := bm.ValidateBlock(block); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tx count. Used to create enough channels to 'join' the go routines
|
// Get the tx count. Used to create enough channels to 'join' the go routines
|
||||||
txCount := len(block.transactions)
|
txCount := len(block.Transactions())
|
||||||
// Locking channel. When it has been fully buffered this method will return
|
// Locking channel. When it has been fully buffered this method will return
|
||||||
lockChan := make(chan bool, txCount)
|
lockChan := make(chan bool, txCount)
|
||||||
|
|
||||||
// Process each transaction/contract
|
// Process each transaction/contract
|
||||||
for _, tx := range block.transactions {
|
for _, tx := range block.Transactions() {
|
||||||
// If there's no recipient, it's a contract
|
// If there's no recipient, it's a contract
|
||||||
if tx.IsContract() {
|
if tx.IsContract() {
|
||||||
go bm.ProcessContract(tx, block, lockChan)
|
go bm.ProcessContract(tx, block, lockChan)
|
||||||
@ -60,11 +61,11 @@ func (bm *BlockManager) ProcessBlock(block *Block) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bm *BlockManager) ValidateBlock(block *Block) error {
|
func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block, lockChan chan bool) {
|
func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.Block, lockChan chan bool) {
|
||||||
// Recovering function in case the VM had any errors
|
// Recovering function in case the VM had any errors
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
27
bytes.go
27
bytes.go
@ -1,27 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NumberToBytes(num uint64, bits int) []byte {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
err := binary.Write(buf, binary.BigEndian, num)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("binary.Write failed:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes()[buf.Len()-(bits / 8):]
|
|
||||||
}
|
|
||||||
|
|
||||||
func BytesToNumber(b []byte) (number uint64) {
|
|
||||||
buf := bytes.NewReader(b)
|
|
||||||
err := binary.Read(buf, binary.LittleEndian, &number)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("binary.Read failed:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
65
contract.go
65
contract.go
@ -1,65 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
_"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Contract struct {
|
|
||||||
t uint32 // contract is always 1
|
|
||||||
amount uint64 // ???
|
|
||||||
state *Trie
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewContract(amount uint64, root []byte) *Contract {
|
|
||||||
contract := &Contract{t: 1, amount: amount}
|
|
||||||
contract.state = NewTrie(Db, string(root))
|
|
||||||
|
|
||||||
return contract
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Contract) MarshalRlp() []byte {
|
|
||||||
return Encode([]interface{}{c.t, c.amount, c.state.root})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Contract) UnmarshalRlp(data []byte) {
|
|
||||||
decoder := NewRlpDecoder(data)
|
|
||||||
|
|
||||||
c.t = uint32(decoder.Get(0).AsUint())
|
|
||||||
c.amount = decoder.Get(1).AsUint()
|
|
||||||
c.state = NewTrie(Db, decoder.Get(2).AsString())
|
|
||||||
}
|
|
||||||
|
|
||||||
type Ether struct {
|
|
||||||
t uint32
|
|
||||||
amount uint64
|
|
||||||
nonce string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEtherFromData(data []byte) *Ether {
|
|
||||||
ether := &Ether{}
|
|
||||||
ether.UnmarshalRlp(data)
|
|
||||||
|
|
||||||
return ether
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Ether) MarshalRlp() []byte {
|
|
||||||
return Encode([]interface{}{e.t, e.amount, e.nonce})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Ether) UnmarshalRlp(data []byte) {
|
|
||||||
t, _ := Decode(data, 0)
|
|
||||||
|
|
||||||
if slice, ok := t.([]interface{}); ok {
|
|
||||||
if t, ok := slice[0].(uint8); ok {
|
|
||||||
e.t = uint32(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
if amount, ok := slice[1].(uint8); ok {
|
|
||||||
e.amount = uint64(amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
if nonce, ok := slice[2].([]uint8); ok {
|
|
||||||
e.nonce = string(nonce)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"github.com/obscuren/sha3"
|
"github.com/obscuren/sha3"
|
||||||
"hash"
|
"hash"
|
||||||
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Dagger struct {
|
type Dagger struct {
|
||||||
@ -40,7 +41,7 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
|
|||||||
|
|
||||||
dag.hash = hash
|
dag.hash = hash
|
||||||
|
|
||||||
obj := BigPow(2, 256)
|
obj := ethutil.BigPow(2, 256)
|
||||||
obj = obj.Div(obj, diff)
|
obj = obj.Div(obj, diff)
|
||||||
|
|
||||||
Found = false
|
Found = false
|
||||||
@ -66,7 +67,7 @@ func DaggerVerify(hash, diff, nonce *big.Int) bool {
|
|||||||
dagger := &Dagger{}
|
dagger := &Dagger{}
|
||||||
dagger.hash = hash
|
dagger.hash = hash
|
||||||
|
|
||||||
obj := BigPow(2, 256)
|
obj := ethutil.BigPow(2, 256)
|
||||||
obj = obj.Div(obj, diff)
|
obj = obj.Div(obj, diff)
|
||||||
|
|
||||||
return dagger.Eval(nonce).Cmp(obj) < 0
|
return dagger.Eval(nonce).Cmp(obj) < 0
|
||||||
@ -114,7 +115,7 @@ func Sum(sha hash.Hash) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dag *Dagger) Eval(N *big.Int) *big.Int {
|
func (dag *Dagger) Eval(N *big.Int) *big.Int {
|
||||||
pow := BigPow(2, 26)
|
pow := ethutil.BigPow(2, 26)
|
||||||
dag.xn = N.Div(N, pow)
|
dag.xn = N.Div(N, pow)
|
||||||
|
|
||||||
sha := sha3.NewKeccak256()
|
sha := sha3.NewKeccak256()
|
||||||
|
56
database.go
56
database.go
@ -1,56 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"os/user"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LDBDatabase struct {
|
|
||||||
db *leveldb.DB
|
|
||||||
trie *Trie
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLDBDatabase() (*LDBDatabase, error) {
|
|
||||||
// This will eventually have to be something like a resource folder.
|
|
||||||
// it works on my system for now. Probably won't work on Windows
|
|
||||||
usr, _ := user.Current()
|
|
||||||
dbPath := path.Join(usr.HomeDir, ".ethereum", "database")
|
|
||||||
|
|
||||||
// Open the db
|
|
||||||
db, err := leveldb.OpenFile(dbPath, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
database := &LDBDatabase{db: db}
|
|
||||||
|
|
||||||
// Bootstrap database. Sets a few defaults; such as the last block
|
|
||||||
database.Bootstrap()
|
|
||||||
|
|
||||||
return database, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *LDBDatabase) Bootstrap() error {
|
|
||||||
//db.trie = NewTrie(db)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *LDBDatabase) Put(key []byte, value []byte) {
|
|
||||||
err := db.db.Put(key, value, nil)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error put", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *LDBDatabase) Close() {
|
|
||||||
// Close the leveldb database
|
|
||||||
db.db.Close()
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
_"testing"
|
|
||||||
_"fmt"
|
|
||||||
)
|
|
||||||
|
|
@ -7,16 +7,18 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"errors"
|
"errors"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"github.com/ethereum/ethdb-go"
|
||||||
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Console struct {
|
type Console struct {
|
||||||
db *MemDatabase
|
db *ethdb.MemDatabase
|
||||||
trie *Trie
|
trie *ethutil.Trie
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsole() *Console {
|
func NewConsole() *Console {
|
||||||
db, _ := NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
trie := NewTrie(db, "")
|
trie := ethutil.NewTrie(db, "")
|
||||||
|
|
||||||
return &Console{db: db, trie: trie}
|
return &Console{db: db, trie: trie}
|
||||||
}
|
}
|
||||||
@ -68,17 +70,19 @@ func (i *Console) ParseInput(input string) bool {
|
|||||||
case "update":
|
case "update":
|
||||||
i.trie.Update(tokens[1], tokens[2])
|
i.trie.Update(tokens[1], tokens[2])
|
||||||
|
|
||||||
fmt.Println(hex.EncodeToString([]byte(i.trie.root)))
|
fmt.Println(hex.EncodeToString([]byte(i.trie.Root)))
|
||||||
case "get":
|
case "get":
|
||||||
fmt.Println(i.trie.Get(tokens[1]))
|
fmt.Println(i.trie.Get(tokens[1]))
|
||||||
case "root":
|
case "root":
|
||||||
fmt.Println(hex.EncodeToString([]byte(i.trie.root)))
|
fmt.Println(hex.EncodeToString([]byte(i.trie.Root)))
|
||||||
case "rawroot":
|
case "rawroot":
|
||||||
fmt.Println(i.trie.root)
|
fmt.Println(i.trie.Root)
|
||||||
case "print":
|
case "print":
|
||||||
i.db.Print()
|
i.db.Print()
|
||||||
case "dag":
|
case "dag":
|
||||||
fmt.Println(DaggerVerify(Big(tokens[1]), BigPow(2, 36), Big(tokens[2])))
|
fmt.Println(DaggerVerify( ethutil.Big(tokens[1]), // hash
|
||||||
|
ethutil.BigPow(2, 36), // diff
|
||||||
|
ethutil.Big(tokens[2])))// nonce
|
||||||
case "exit", "quit", "q":
|
case "exit", "quit", "q":
|
||||||
return false
|
return false
|
||||||
case "help":
|
case "help":
|
||||||
|
62
encoding.go
62
encoding.go
@ -1,62 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"strings"
|
|
||||||
_"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CompactEncode(hexSlice []int) string {
|
|
||||||
terminator := 0
|
|
||||||
if hexSlice[len(hexSlice)-1] == 16 {
|
|
||||||
terminator = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if terminator == 1 {
|
|
||||||
hexSlice = hexSlice[:len(hexSlice)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
oddlen := len(hexSlice) % 2
|
|
||||||
flags := 2 * terminator + oddlen
|
|
||||||
if oddlen != 0 {
|
|
||||||
hexSlice = append([]int{flags}, hexSlice...)
|
|
||||||
} else {
|
|
||||||
hexSlice = append([]int{flags, 0}, hexSlice...)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buff bytes.Buffer
|
|
||||||
for i := 0; i < len(hexSlice); i+=2 {
|
|
||||||
buff.WriteByte(byte(16 * hexSlice[i] + hexSlice[i+1]))
|
|
||||||
}
|
|
||||||
|
|
||||||
return buff.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func CompactDecode(str string) []int {
|
|
||||||
base := CompactHexDecode(str)
|
|
||||||
base = base[:len(base)-1]
|
|
||||||
if base[0] >= 2 {// && base[len(base)-1] != 16 {
|
|
||||||
base = append(base, 16)
|
|
||||||
}
|
|
||||||
if base[0] % 2 == 1 {
|
|
||||||
base = base[1:]
|
|
||||||
} else {
|
|
||||||
base = base[2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
|
|
||||||
func CompactHexDecode(str string) []int {
|
|
||||||
base := "0123456789abcdef"
|
|
||||||
hexSlice := make([]int, 0)
|
|
||||||
|
|
||||||
enc := hex.EncodeToString([]byte(str))
|
|
||||||
for _, v := range enc {
|
|
||||||
hexSlice = append(hexSlice, strings.IndexByte(base, byte(v)))
|
|
||||||
}
|
|
||||||
hexSlice = append(hexSlice, 16)
|
|
||||||
|
|
||||||
return hexSlice
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCompactEncode(t *testing.T) {
|
|
||||||
test1 := []int{1,2,3,4,5}
|
|
||||||
if res := CompactEncode(test1); res != "\x11\x23\x45" {
|
|
||||||
t.Error(fmt.Sprintf("even compact encode failed. Got: %q", res))
|
|
||||||
}
|
|
||||||
|
|
||||||
test2 := []int{0, 1, 2, 3, 4, 5}
|
|
||||||
if res := CompactEncode(test2); res != "\x00\x01\x23\x45" {
|
|
||||||
t.Error(fmt.Sprintf("odd compact encode failed. Got: %q", res))
|
|
||||||
}
|
|
||||||
|
|
||||||
test3 := []int{0, 15, 1, 12, 11, 8, /*term*/16}
|
|
||||||
if res := CompactEncode(test3); res != "\x20\x0f\x1c\xb8" {
|
|
||||||
t.Error(fmt.Sprintf("odd terminated compact encode failed. Got: %q", res))
|
|
||||||
}
|
|
||||||
|
|
||||||
test4 := []int{15, 1, 12, 11, 8, /*term*/16}
|
|
||||||
if res := CompactEncode(test4); res != "\x3f\x1c\xb8" {
|
|
||||||
t.Error(fmt.Sprintf("even terminated compact encode failed. Got: %q", res))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func TestCompactHexDecode(t *testing.T) {
|
|
||||||
exp := []int{7, 6, 6, 5, 7, 2, 6, 2, 16}
|
|
||||||
res := CompactHexDecode("verb")
|
|
||||||
|
|
||||||
if !CompareIntSlice(res, exp) {
|
|
||||||
t.Error("Error compact hex decode. Expected", exp, "got", res)
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"runtime"
|
"runtime"
|
||||||
"log"
|
"log"
|
||||||
_"math/big"
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Debug = true
|
const Debug = true
|
||||||
@ -39,7 +39,7 @@ func RegisterInterupts(s *Server) {
|
|||||||
func main() {
|
func main() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
||||||
InitFees()
|
ethutil.InitFees()
|
||||||
|
|
||||||
Init()
|
Init()
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ func main() {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
res := dagger.Search(Big("0"), BigPow(2, 36))
|
res := dagger.Search(ethutil.Big("0"), ethutil.BigPow(2, 36))
|
||||||
server.Broadcast("block", Encode(res.String()))
|
server.Broadcast("block", Encode(res.String()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
34
genesis.go
34
genesis.go
@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the special genesis block.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var GenisisHeader = []interface{}{
|
|
||||||
// Block number
|
|
||||||
uint32(0),
|
|
||||||
// Previous hash (none)
|
|
||||||
"",
|
|
||||||
// Sha of uncles
|
|
||||||
string(Sha256Bin(Encode([]interface{}{}))),
|
|
||||||
// Coinbase
|
|
||||||
"",
|
|
||||||
// Root state
|
|
||||||
"",
|
|
||||||
// Sha of transactions
|
|
||||||
string(Sha256Bin(Encode([]interface{}{}))),
|
|
||||||
// Difficulty
|
|
||||||
uint32(math.Pow(2, 36)),
|
|
||||||
// Time
|
|
||||||
uint64(1),
|
|
||||||
// Nonce
|
|
||||||
uint32(0),
|
|
||||||
// Extra
|
|
||||||
"",
|
|
||||||
}
|
|
||||||
|
|
||||||
var Genesis = []interface{}{ GenisisHeader, []interface{}{}, []interface{}{} }
|
|
@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a test memory database. Do not use for any production it does not get persisted
|
|
||||||
*/
|
|
||||||
type MemDatabase struct {
|
|
||||||
db map[string][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMemDatabase() (*MemDatabase, error) {
|
|
||||||
db := &MemDatabase{db: make(map[string][]byte)}
|
|
||||||
|
|
||||||
return db, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *MemDatabase) Put(key []byte, value []byte) {
|
|
||||||
db.db[string(key)] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *MemDatabase) Get(key []byte) ([]byte, error) {
|
|
||||||
return db.db[string(key)], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *MemDatabase) Print() {
|
|
||||||
for key, val := range db.db {
|
|
||||||
fmt.Printf("%x(%d):", key, len(key))
|
|
||||||
decoded := DecodeNode(val)
|
|
||||||
PrintSlice(decoded)
|
|
||||||
}
|
|
||||||
}
|
|
98
parsing.go
98
parsing.go
@ -1,98 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Op codes
|
|
||||||
var OpCodes = map[string]string{
|
|
||||||
"STOP": "0",
|
|
||||||
"ADD": "1",
|
|
||||||
"MUL": "2",
|
|
||||||
"SUB": "3",
|
|
||||||
"DIV": "4",
|
|
||||||
"SDIV": "5",
|
|
||||||
"MOD": "6",
|
|
||||||
"SMOD": "7",
|
|
||||||
"EXP": "8",
|
|
||||||
"NEG": "9",
|
|
||||||
"LT": "10",
|
|
||||||
"LE": "11",
|
|
||||||
"GT": "12",
|
|
||||||
"GE": "13",
|
|
||||||
"EQ": "14",
|
|
||||||
"NOT": "15",
|
|
||||||
"MYADDRESS": "16",
|
|
||||||
"TXSENDER": "17",
|
|
||||||
|
|
||||||
|
|
||||||
"PUSH": "48",
|
|
||||||
"POP": "49",
|
|
||||||
"LOAD": "54",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func CompileInstr(s string) (string, error) {
|
|
||||||
tokens := strings.Split(s, " ")
|
|
||||||
if OpCodes[tokens[0]] == "" {
|
|
||||||
return s, 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
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCompile(t *testing.T) {
|
|
||||||
instr, err := CompileInstr("PUSH")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Failed compiling instruction")
|
|
||||||
}
|
|
||||||
|
|
||||||
calc := (48 + 0 * 256 + 0 * 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")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInvalidInstr(t *testing.T) {
|
|
||||||
}
|
|
||||||
|
|
3
rlp.go
3
rlp.go
@ -5,6 +5,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RlpEncoder struct {
|
type RlpEncoder struct {
|
||||||
@ -54,7 +55,7 @@ func (attr *RlpDataAttribute) AsUint() uint64 {
|
|||||||
|
|
||||||
func (attr *RlpDataAttribute) AsBigInt() *big.Int {
|
func (attr *RlpDataAttribute) AsBigInt() *big.Int {
|
||||||
if a, ok := attr.dataAttrib.([]byte); ok {
|
if a, ok := attr.dataAttrib.([]byte); ok {
|
||||||
return Big(string(a))
|
return ethutil.Big(string(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
return big.NewInt(0)
|
return big.NewInt(0)
|
||||||
|
10
server.go
10
server.go
@ -5,15 +5,15 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"log"
|
"log"
|
||||||
_"time"
|
_"time"
|
||||||
|
"github.com/ethereum/ethdb-go"
|
||||||
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Db *LDBDatabase
|
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
// Channel for shutting down the server
|
// Channel for shutting down the server
|
||||||
shutdownChan chan bool
|
shutdownChan chan bool
|
||||||
// DB interface
|
// DB interface
|
||||||
db *LDBDatabase
|
db *ethdb.LDBDatabase
|
||||||
// Block manager for processing new blocks and managing the block chain
|
// Block manager for processing new blocks and managing the block chain
|
||||||
blockManager *BlockManager
|
blockManager *BlockManager
|
||||||
// Peers (NYI)
|
// Peers (NYI)
|
||||||
@ -21,12 +21,12 @@ type Server struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewServer() (*Server, error) {
|
func NewServer() (*Server, error) {
|
||||||
db, err := NewLDBDatabase()
|
db, err := ethdb.NewLDBDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
Db = db
|
ethutil.SetConfig(db)
|
||||||
|
|
||||||
server := &Server{
|
server := &Server{
|
||||||
shutdownChan: make(chan bool),
|
shutdownChan: make(chan bool),
|
||||||
|
206
transaction.go
206
transaction.go
@ -1,206 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"fmt"
|
|
||||||
"github.com/obscuren/secp256k1-go"
|
|
||||||
_"encoding/hex"
|
|
||||||
_"crypto/sha256"
|
|
||||||
_ "bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
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 ContractFee *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 {
|
|
||||||
nonce string
|
|
||||||
sender string
|
|
||||||
recipient string
|
|
||||||
value uint64
|
|
||||||
fee uint32
|
|
||||||
data []string
|
|
||||||
memory []int
|
|
||||||
lastTx string
|
|
||||||
v uint32
|
|
||||||
r, s []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTransaction(to string, value uint64, data []string) *Transaction {
|
|
||||||
tx := Transaction{sender: "1234567890", recipient: to, value: value}
|
|
||||||
tx.nonce = "0"
|
|
||||||
tx.fee = 0//uint32((ContractFee + MemoryFee * float32(len(tx.data))) * 1e8)
|
|
||||||
tx.lastTx = "0"
|
|
||||||
|
|
||||||
// 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\n", i+1, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.data[i] = instr
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Sign([]byte("privkey"))
|
|
||||||
tx.Sender()
|
|
||||||
|
|
||||||
|
|
||||||
return &tx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) Hash() []byte {
|
|
||||||
preEnc := []interface{}{
|
|
||||||
tx.nonce,
|
|
||||||
tx.recipient,
|
|
||||||
tx.value,
|
|
||||||
tx.fee,
|
|
||||||
tx.data,
|
|
||||||
}
|
|
||||||
|
|
||||||
return Sha256Bin(Encode(preEnc))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) IsContract() bool {
|
|
||||||
return tx.recipient == ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) Signature(key []byte) []byte {
|
|
||||||
hash := tx.Hash()
|
|
||||||
sec := Sha256Bin(key)
|
|
||||||
|
|
||||||
sig, _ := secp256k1.Sign(hash, sec)
|
|
||||||
|
|
||||||
return sig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) PublicKey() []byte {
|
|
||||||
hash := Sha256Bin(tx.Hash())
|
|
||||||
sig := append(tx.r, tx.s...)
|
|
||||||
|
|
||||||
pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
|
|
||||||
|
|
||||||
return pubkey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) Sender() []byte {
|
|
||||||
pubkey := tx.PublicKey()
|
|
||||||
|
|
||||||
// Validate the returned key.
|
|
||||||
// Return nil if public key isn't in full format (04 = full, 03 = compact)
|
|
||||||
if pubkey[0] != 4 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return Sha256Bin(pubkey[1:65])[12:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) Sign(privk []byte) {
|
|
||||||
sig := tx.Signature(privk)
|
|
||||||
|
|
||||||
// Add 27 so we get either 27 or 28 (for positive and negative)
|
|
||||||
tx.v = uint32(sig[64]) + 27
|
|
||||||
tx.r = sig[:32]
|
|
||||||
tx.s = sig[32:65]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) MarshalRlp() []byte {
|
|
||||||
// Prepare the transaction for serialization
|
|
||||||
preEnc := []interface{}{
|
|
||||||
tx.nonce,
|
|
||||||
tx.recipient,
|
|
||||||
tx.value,
|
|
||||||
tx.fee,
|
|
||||||
tx.data,
|
|
||||||
tx.v,
|
|
||||||
tx.r,
|
|
||||||
tx.s,
|
|
||||||
}
|
|
||||||
|
|
||||||
return Encode(preEnc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) UnmarshalRlp(data []byte) {
|
|
||||||
decoder := NewRlpDecoder(data)
|
|
||||||
|
|
||||||
tx.nonce = decoder.Get(0).AsString()
|
|
||||||
tx.recipient = decoder.Get(0).AsString()
|
|
||||||
tx.value = decoder.Get(2).AsUint()
|
|
||||||
tx.fee = uint32(decoder.Get(3).AsUint())
|
|
||||||
|
|
||||||
d := decoder.Get(4)
|
|
||||||
tx.data = make([]string, d.Length())
|
|
||||||
fmt.Println(d.Get(0))
|
|
||||||
for i := 0; i < d.Length(); i++ {
|
|
||||||
tx.data[i] = d.Get(i).AsString()
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.v = uint32(decoder.Get(5).AsUint())
|
|
||||||
tx.r = decoder.Get(6).AsBytes()
|
|
||||||
tx.s = decoder.Get(7).AsBytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitFees() {
|
|
||||||
// Base for 2**60
|
|
||||||
b60 := new(big.Int)
|
|
||||||
b60.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
|
|
||||||
// Base for 2**80
|
|
||||||
b80 := new(big.Int)
|
|
||||||
b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0))
|
|
||||||
|
|
||||||
StepFee.Exp(big.NewInt(10), big.NewInt(16), big.NewInt(0))
|
|
||||||
//StepFee.Div(b60, big.NewInt(64))
|
|
||||||
//fmt.Println("StepFee:", StepFee)
|
|
||||||
|
|
||||||
TxFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
|
|
||||||
//fmt.Println("TxFee:", TxFee)
|
|
||||||
|
|
||||||
ContractFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
|
|
||||||
//fmt.Println("ContractFee:", ContractFee)
|
|
||||||
|
|
||||||
MemFee.Div(b60, big.NewInt(4))
|
|
||||||
//fmt.Println("MemFee:", MemFee)
|
|
||||||
|
|
||||||
DataFee.Div(b60, big.NewInt(16))
|
|
||||||
//fmt.Println("DataFee:", DataFee)
|
|
||||||
|
|
||||||
CryptoFee.Div(b60, big.NewInt(16))
|
|
||||||
//fmt.Println("CrytoFee:", CryptoFee)
|
|
||||||
|
|
||||||
ExtroFee.Div(b60, big.NewInt(16))
|
|
||||||
//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)
|
|
||||||
}
|
|
203
trie.go
203
trie.go
@ -1,203 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Database interface
|
|
||||||
type Database interface {
|
|
||||||
Put(key []byte, value []byte)
|
|
||||||
Get(key []byte) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Trie helper functions
|
|
||||||
*/
|
|
||||||
// Helper function for printing out the raw contents of a slice
|
|
||||||
func PrintSlice(slice []string) {
|
|
||||||
fmt.Printf("[")
|
|
||||||
for i, val := range slice {
|
|
||||||
fmt.Printf("%q", val)
|
|
||||||
if i != len(slice)-1 { fmt.Printf(",") }
|
|
||||||
}
|
|
||||||
fmt.Printf("]\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RLP Decodes a node in to a [2] or [17] string slice
|
|
||||||
func DecodeNode(data []byte) []string {
|
|
||||||
dec, _ := Decode(data, 0)
|
|
||||||
if slice, ok := dec.([]interface{}); ok {
|
|
||||||
strSlice := make([]string, len(slice))
|
|
||||||
|
|
||||||
for i, s := range slice {
|
|
||||||
if str, ok := s.([]byte); ok {
|
|
||||||
strSlice[i] = string(str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strSlice
|
|
||||||
} else {
|
|
||||||
fmt.Printf("It wasn't a []. It's a %T\n", dec)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// A (modified) Radix Trie implementation
|
|
||||||
type Trie struct {
|
|
||||||
root string
|
|
||||||
db Database
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTrie(db Database, root string) *Trie {
|
|
||||||
return &Trie{db: db, root: root}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Public (query) interface functions
|
|
||||||
*/
|
|
||||||
func (t *Trie) Update(key string, value string) {
|
|
||||||
k := CompactHexDecode(key)
|
|
||||||
|
|
||||||
t.root = t.UpdateState(t.root, k, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Trie) Get(key string) string {
|
|
||||||
k := CompactHexDecode(key)
|
|
||||||
|
|
||||||
return t.GetState(t.root, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* State functions (shouldn't be needed directly).
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Helper function for printing a node (using fetch, decode and slice printing)
|
|
||||||
func (t *Trie) PrintNode(n string) {
|
|
||||||
data, _ := t.db.Get([]byte(n))
|
|
||||||
d := DecodeNode(data)
|
|
||||||
PrintSlice(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the state of an object
|
|
||||||
func (t *Trie) GetState(node string, key []int) string {
|
|
||||||
// Return the node if key is empty (= found)
|
|
||||||
if len(key) == 0 || node == "" {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the encoded node from the db
|
|
||||||
n, err := t.db.Get([]byte(node))
|
|
||||||
if err != nil { fmt.Println("Error in GetState for node", node, "with key", key); return "" }
|
|
||||||
|
|
||||||
// Decode it
|
|
||||||
currentNode := DecodeNode(n)
|
|
||||||
|
|
||||||
if len(currentNode) == 0 {
|
|
||||||
return ""
|
|
||||||
} else if len(currentNode) == 2 {
|
|
||||||
// Decode the key
|
|
||||||
k := CompactDecode(currentNode[0])
|
|
||||||
v := currentNode[1]
|
|
||||||
|
|
||||||
if len(key) >= len(k) && CompareIntSlice(k, key[:len(k)]) {
|
|
||||||
return t.GetState(v, key[len(k):])
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
} else if len(currentNode) == 17 {
|
|
||||||
return t.GetState(currentNode[key[0]], key[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// It shouldn't come this far
|
|
||||||
fmt.Println("GetState unexpected return")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inserts a new sate or delete a state based on the value
|
|
||||||
func (t *Trie) UpdateState(node string, key []int, value string) string {
|
|
||||||
if value != "" {
|
|
||||||
return t.InsertState(node, key, value)
|
|
||||||
} else {
|
|
||||||
// delete it
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper around the regular db "Put" which generates a key and value
|
|
||||||
func (t *Trie) Put(node interface{}) []byte {
|
|
||||||
enc := Encode(node)
|
|
||||||
var sha []byte
|
|
||||||
sha = Sha256Bin(enc)
|
|
||||||
|
|
||||||
t.db.Put([]byte(sha), enc)
|
|
||||||
|
|
||||||
return sha
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Trie) InsertState(node string, key []int, value string) string {
|
|
||||||
if len(key) == 0 {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// New node
|
|
||||||
if node == "" {
|
|
||||||
newNode := []string{ CompactEncode(key), value }
|
|
||||||
|
|
||||||
return string(t.Put(newNode))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the encoded node from the db
|
|
||||||
n, err := t.db.Get([]byte(node))
|
|
||||||
if err != nil { fmt.Println("Error InsertState", err); return "" }
|
|
||||||
|
|
||||||
// Decode it
|
|
||||||
currentNode := DecodeNode(n)
|
|
||||||
// Check for "special" 2 slice type node
|
|
||||||
if len(currentNode) == 2 {
|
|
||||||
// Decode the key
|
|
||||||
k := CompactDecode(currentNode[0])
|
|
||||||
v := currentNode[1]
|
|
||||||
|
|
||||||
// Matching key pair (ie. there's already an object with this key)
|
|
||||||
if CompareIntSlice(k, key) {
|
|
||||||
return string(t.Put([]string{ CompactEncode(key), value }))
|
|
||||||
}
|
|
||||||
|
|
||||||
var newHash string
|
|
||||||
matchingLength := MatchingNibbleLength(key, k)
|
|
||||||
if matchingLength == len(k) {
|
|
||||||
// Insert the hash, creating a new node
|
|
||||||
newHash = t.InsertState(v, key[matchingLength:], value)
|
|
||||||
} else {
|
|
||||||
// Expand the 2 length slice to a 17 length slice
|
|
||||||
oldNode := t.InsertState("", k[matchingLength+1:], v)
|
|
||||||
newNode := t.InsertState("", key[matchingLength+1:], value)
|
|
||||||
// Create an expanded slice
|
|
||||||
scaledSlice := make([]string, 17)
|
|
||||||
// Set the copied and new node
|
|
||||||
scaledSlice[k[matchingLength]] = oldNode
|
|
||||||
scaledSlice[key[matchingLength]] = newNode
|
|
||||||
|
|
||||||
newHash = string(t.Put(scaledSlice))
|
|
||||||
}
|
|
||||||
|
|
||||||
if matchingLength == 0 {
|
|
||||||
// End of the chain, return
|
|
||||||
return newHash
|
|
||||||
} else {
|
|
||||||
newNode := []string{ CompactEncode(key[:matchingLength]), newHash }
|
|
||||||
return string(t.Put(newNode))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Copy the current node over to the new node and replace the first nibble in the key
|
|
||||||
newNode := make([]string, 17); copy(newNode, currentNode)
|
|
||||||
newNode[key[0]] = t.InsertState(currentNode[key[0]], key[1:], value)
|
|
||||||
|
|
||||||
return string(t.Put(newNode))
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
59
trie_test.go
59
trie_test.go
@ -1,59 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"encoding/hex"
|
|
||||||
_"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTriePut(t *testing.T) {
|
|
||||||
db, err := NewMemDatabase()
|
|
||||||
trie := NewTrie(db, "")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error starting db")
|
|
||||||
}
|
|
||||||
|
|
||||||
key := trie.Put([]byte("testing node"))
|
|
||||||
|
|
||||||
data, err := db.Get(key)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Nothing at node")
|
|
||||||
}
|
|
||||||
|
|
||||||
s, _ := Decode(data, 0)
|
|
||||||
if str, ok := s.([]byte); ok {
|
|
||||||
if string(str) != "testing node" {
|
|
||||||
t.Error("Wrong value node", str)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Error("Invalid return type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTrieUpdate(t *testing.T) {
|
|
||||||
db, err := NewMemDatabase()
|
|
||||||
trie := NewTrie(db, "")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error starting db")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
trie.Update("doe", "reindeer")
|
|
||||||
trie.Update("dog", "puppy")
|
|
||||||
/*
|
|
||||||
data, _ := db.Get([]byte(trie.root))
|
|
||||||
data, _ = db.Get([]byte(DecodeNode(data)[1]))
|
|
||||||
data, _ = db.Get([]byte(DecodeNode(data)[7]))
|
|
||||||
PrintSlice(DecodeNode(data))
|
|
||||||
*/
|
|
||||||
|
|
||||||
trie.Update("dogglesworth", "cat")
|
|
||||||
root := hex.EncodeToString([]byte(trie.root))
|
|
||||||
req := "e378927bfc1bd4f01a2e8d9f59bd18db8a208bb493ac0b00f93ce51d4d2af76c"
|
|
||||||
if root != req {
|
|
||||||
t.Error("trie.root do not match, expected", req, "got", root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
63
util.go
63
util.go
@ -1,63 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
_"fmt"
|
|
||||||
_"math"
|
|
||||||
"github.com/obscuren/sha3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Uitoa(i uint32) string {
|
|
||||||
return strconv.FormatUint(uint64(i), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sha256Hex(data []byte) string {
|
|
||||||
hash := sha256.Sum256(data)
|
|
||||||
|
|
||||||
return hex.EncodeToString(hash[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sha256Bin(data []byte) []byte {
|
|
||||||
hash := sha256.Sum256(data)
|
|
||||||
|
|
||||||
return hash[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sha3Bin(data []byte) []byte {
|
|
||||||
d := sha3.NewKeccak224()
|
|
||||||
d.Reset()
|
|
||||||
d.Write(data)
|
|
||||||
|
|
||||||
return d.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function for comparing slices
|
|
||||||
func CompareIntSlice(a, b []int) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, v := range a {
|
|
||||||
if v != b[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the amount of nibbles that match each other from 0 ...
|
|
||||||
func MatchingNibbleLength(a, b []int) int {
|
|
||||||
i := 0
|
|
||||||
for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) {
|
|
||||||
i+=1
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Println(a, b, i-1)
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func Hex(d []byte) string {
|
|
||||||
return hex.EncodeToString(d)
|
|
||||||
}
|
|
22
vm.go
22
vm.go
@ -1,12 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_"math"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"fmt"
|
"fmt"
|
||||||
_"strconv"
|
|
||||||
_ "encoding/hex"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"github.com/ethereum/ethutil-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Op codes
|
// Op codes
|
||||||
@ -93,7 +91,7 @@ func (st *Stack) Popn() (*big.Int, *big.Int) {
|
|||||||
strs := st.data[s-2:]
|
strs := st.data[s-2:]
|
||||||
st.data = st.data[:s-2]
|
st.data = st.data[:s-2]
|
||||||
|
|
||||||
return Big(strs[0]), Big(strs[1])
|
return ethutil.Big(strs[0]), ethutil.Big(strs[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Push(d string) {
|
func (st *Stack) Push(d string) {
|
||||||
@ -114,7 +112,8 @@ func NewVm() *Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *Vm) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
|
func (vm *Vm) ProcContract( tx *ethutil.Transaction,
|
||||||
|
block *ethutil.Block, cb TxCallback) {
|
||||||
// Instruction pointer
|
// Instruction pointer
|
||||||
pc := 0
|
pc := 0
|
||||||
|
|
||||||
@ -124,7 +123,7 @@ func (vm *Vm) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Pow256 := BigPow(2, 256)
|
Pow256 := ethutil.BigPow(2, 256)
|
||||||
|
|
||||||
//fmt.Printf("# op arg\n")
|
//fmt.Printf("# op arg\n")
|
||||||
out:
|
out:
|
||||||
@ -134,7 +133,8 @@ out:
|
|||||||
// XXX Should Instr return big int slice instead of string slice?
|
// XXX Should Instr return big int slice instead of string slice?
|
||||||
// Get the next instruction from the contract
|
// Get the next instruction from the contract
|
||||||
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
|
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
|
||||||
op, _, _ := Instr(contract.state.Get(string(NumberToBytes(uint64(pc), 32))))
|
nb := ethutil.NumberToBytes(uint64(pc), 32)
|
||||||
|
op, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
|
||||||
|
|
||||||
if !cb(0) { break }
|
if !cb(0) { break }
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ out:
|
|||||||
|
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oNEG:
|
case oNEG:
|
||||||
base.Sub(Pow256, Big(vm.stack.Pop()))
|
base.Sub(Pow256, ethutil.Big(vm.stack.Pop()))
|
||||||
vm.stack.Push(base.String())
|
vm.stack.Push(base.String())
|
||||||
case oLT:
|
case oLT:
|
||||||
x, y := vm.stack.Popn()
|
x, y := vm.stack.Popn()
|
||||||
@ -245,18 +245,18 @@ out:
|
|||||||
case oMYADDRESS:
|
case oMYADDRESS:
|
||||||
vm.stack.Push(string(tx.Hash()))
|
vm.stack.Push(string(tx.Hash()))
|
||||||
case oTXSENDER:
|
case oTXSENDER:
|
||||||
vm.stack.Push(tx.sender)
|
vm.stack.Push(string(tx.Sender()))
|
||||||
case oPUSH:
|
case oPUSH:
|
||||||
// Get the next entry and pushes the value on the stack
|
// Get the next entry and pushes the value on the stack
|
||||||
pc++
|
pc++
|
||||||
vm.stack.Push(contract.state.Get(string(NumberToBytes(uint64(pc), 32))))
|
vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32))))
|
||||||
case oPOP:
|
case oPOP:
|
||||||
// Pop current value of the stack
|
// Pop current value of the stack
|
||||||
vm.stack.Pop()
|
vm.stack.Pop()
|
||||||
case oLOAD:
|
case oLOAD:
|
||||||
// Load instruction X on the stack
|
// Load instruction X on the stack
|
||||||
i, _ := strconv.Atoi(vm.stack.Pop())
|
i, _ := strconv.Atoi(vm.stack.Pop())
|
||||||
vm.stack.Push(contract.state.Get(string(NumberToBytes(uint64(i), 32))))
|
vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32))))
|
||||||
case oSTOP:
|
case oSTOP:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user