mirror of https://github.com/ethereum/go-ethereum
parent
f6fa4f8879
commit
8bbf879cb3
@ -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 |
||||
} |
@ -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 |
||||
} |
||||
} |
@ -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 |
||||
} |
@ -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) |
||||
} |
||||
} |
||||
} |
@ -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" |
||||
) |
||||
|
@ -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) |
||||
} |
||||
} |
@ -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) |
||||
} |
||||
} |
@ -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) { |
||||
} |
||||
|
@ -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)
|
||||
} |
@ -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 "" |
||||
} |
||||
|
@ -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) |
||||
} |
||||
} |
||||
|
@ -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) |
||||
} |
Loading…
Reference in new issue