Merge branch 'release/poc5-rc9'

This commit is contained in:
obscuren 2014-05-26 00:42:07 +02:00
commit b1463b2dc2
23 changed files with 438 additions and 210 deletions

View File

@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof
of Concept 5.0 RC8". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
of Concept 5.0 RC9". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
Ethereum Go is split up in several sub packages Please refer to each
individual package for more information.

View File

@ -1,6 +1,7 @@
package ethchain
import (
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
@ -55,6 +56,7 @@ type Block struct {
Nonce []byte
// List of transactions and/or contracts
transactions []*Transaction
receipts []*Receipt
TxSha []byte
}
@ -84,24 +86,20 @@ func CreateBlock(root interface{},
base []byte,
Difficulty *big.Int,
Nonce []byte,
extra string,
txes []*Transaction) *Block {
extra string) *Block {
block := &Block{
// Slice of transactions to include in this block
transactions: txes,
PrevHash: prevHash,
Coinbase: base,
Difficulty: Difficulty,
Nonce: Nonce,
Time: time.Now().Unix(),
Extra: extra,
UncleSha: EmptyShaList,
GasUsed: new(big.Int),
MinGasPrice: new(big.Int),
GasLimit: new(big.Int),
PrevHash: prevHash,
Coinbase: base,
Difficulty: Difficulty,
Nonce: Nonce,
Time: time.Now().Unix(),
Extra: extra,
UncleSha: EmptyShaList,
GasUsed: new(big.Int),
MinGasPrice: new(big.Int),
GasLimit: new(big.Int),
}
block.SetTransactions(txes)
block.SetUncles([]*Block{})
block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root))
@ -115,7 +113,10 @@ func (block *Block) Hash() []byte {
}
func (block *Block) HashNoNonce() []byte {
return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra}))
return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash,
block.UncleSha, block.Coinbase, block.state.trie.Root,
block.TxSha, block.Difficulty, block.Number, block.MinGasPrice,
block.GasLimit, block.GasUsed, block.Time, block.Extra}))
}
func (block *Block) State() *State {
@ -161,6 +162,16 @@ func (block *Block) BlockInfo() BlockInfo {
return bi
}
func (self *Block) GetTransaction(hash []byte) *Transaction {
for _, receipt := range self.receipts {
if bytes.Compare(receipt.Tx.Hash(), hash) == 0 {
return receipt.Tx
}
}
return nil
}
// Sync the block's state and contract respectively
func (block *Block) Sync() {
block.state.Sync()
@ -172,15 +183,15 @@ func (block *Block) Undo() {
}
/////// Block Encoding
func (block *Block) rlpTxs() interface{} {
func (block *Block) rlpReceipts() interface{} {
// Marshal the transactions of this block
encTx := make([]interface{}, len(block.transactions))
for i, tx := range block.transactions {
encR := make([]interface{}, len(block.receipts))
for i, r := range block.receipts {
// Cast it to a string (safe)
encTx[i] = tx.RlpData()
encR[i] = r.RlpData()
}
return encTx
return encR
}
func (block *Block) rlpUncles() interface{} {
@ -201,7 +212,12 @@ func (block *Block) SetUncles(uncles []*Block) {
block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles()))
}
func (block *Block) SetTransactions(txs []*Transaction) {
func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) {
self.receipts = receipts
self.setTransactions(txs)
}
func (block *Block) setTransactions(txs []*Transaction) {
block.transactions = txs
trie := ethutil.NewTrie(ethutil.Config.Db, "")
@ -221,7 +237,7 @@ func (block *Block) SetTransactions(txs []*Transaction) {
}
func (block *Block) Value() *ethutil.Value {
return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()})
return ethutil.NewValue([]interface{}{block.header(), block.rlpReceipts(), block.rlpUncles()})
}
func (block *Block) RlpEncode() []byte {
@ -245,6 +261,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt()
block.Number = header.Get(6).BigInt()
//fmt.Printf("#%v : %x\n", block.Number, block.Coinbase)
block.MinGasPrice = header.Get(7).BigInt()
block.GasLimit = header.Get(8).BigInt()
block.GasUsed = header.Get(9).BigInt()
@ -255,12 +272,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
// Tx list might be empty if this is an uncle. Uncles only have their
// header set.
if decoder.Get(1).IsNil() == false { // Yes explicitness
txes := decoder.Get(1)
block.transactions = make([]*Transaction, txes.Len())
for i := 0; i < txes.Len(); i++ {
tx := NewTransactionFromValue(txes.Get(i))
block.transactions[i] = tx
receipts := decoder.Get(1)
block.transactions = make([]*Transaction, receipts.Len())
block.receipts = make([]*Receipt, receipts.Len())
for i := 0; i < receipts.Len(); i++ {
receipt := NewRecieptFromValue(receipts.Get(i))
block.transactions[i] = receipt.Tx
block.receipts[i] = receipt
}
}
@ -299,6 +317,10 @@ func (block *Block) GetRoot() interface{} {
return block.state.trie.Root
}
func (self *Block) Receipts() []*Receipt {
return self.receipts
}
func (block *Block) header() []interface{} {
return []interface{}{
// Sha of the previous block
@ -346,6 +368,7 @@ func (block *Block) String() string {
Time: %v
Extra: %v
Nonce: %x
NumTx: %v
`,
block.Hash(),
block.PrevHash,
@ -360,5 +383,7 @@ func (block *Block) String() string {
block.GasUsed,
block.Time,
block.Extra,
block.Nonce)
block.Nonce,
len(block.transactions),
)
}

View File

@ -36,7 +36,7 @@ func (bc *BlockChain) Genesis() *Block {
return bc.genesisBlock
}
func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
var root interface{}
var lastBlockTime int64
hash := ZeroHash256
@ -53,8 +53,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
coinbase,
ethutil.BigPow(2, 32),
nil,
"",
txs)
"")
if bc.CurrentBlock != nil {
var mul *big.Int
@ -272,16 +271,18 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block {
func AddTestNetFunds(block *Block) {
for _, addr := range []string{
"8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin
"e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex
"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman
"8a40bfaa73256b60764c1bf40675a99083efb075",
"e4157b34ea9615cfbde6b4fda419828124b70c78",
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df",
"6c386a4b26f73c802f34673f7248bb118f97424a",
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
"2ef47100e0787b915105fd5e3f4ff6752079d5cb",
"e6716f9544a56c530d868e4bfbacb172315bdead",
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
} {
codedAddr := ethutil.FromHex(addr)
account := block.state.GetAccount(codedAddr)
account.Amount = ethutil.BigPow(2, 200)
account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200)
block.state.UpdateStateObject(account)
}
log.Printf("%x\n", block.RlpEncode())

View File

@ -50,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) {
}
func NewTestManager() *TestManager {
ethutil.ReadConfig(".ethtest", ethutil.LogStd)
ethutil.ReadConfig(".ethtest", ethutil.LogStd, "")
db, err := ethdb.NewMemDatabase()
if err != nil {
@ -74,7 +74,7 @@ func NewTestManager() *TestManager {
func (tm *TestManager) AddFakeBlock(blk []byte) error {
block := NewBlockFromBytes(blk)
tm.Blocks = append(tm.Blocks, block)
err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false)
err := tm.StateManager().Process(block, false)
return err
}
func (tm *TestManager) CreateChain1() error {

View File

@ -23,7 +23,7 @@ var GenesisHeader = []interface{}{
// Root state
"",
// tx sha
ZeroHash256,
"",
// Difficulty
ethutil.BigPow(2, 22),
// Number

View File

@ -99,7 +99,21 @@ func (s *State) Cmp(other *State) bool {
}
func (s *State) Copy() *State {
return NewState(s.trie.Copy())
state := NewState(s.trie.Copy())
for k, subState := range s.states {
state.states[k] = subState.Copy()
}
return state
}
func (s *State) Snapshot() *State {
return s.Copy()
}
func (s *State) Revert(snapshot *State) {
s.trie = snapshot.trie
s.states = snapshot.states
}
func (s *State) Put(key, object []byte) {

View File

@ -84,7 +84,7 @@ func (sm *StateManager) BlockChain() *BlockChain {
return sm.bc
}
func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject {
func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject {
contract := MakeContract(tx, state)
if contract != nil {
state.states[string(tx.CreationAddress())] = contract.state
@ -97,40 +97,74 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) {
func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) {
// Process each transaction/contract
var receipts []*Receipt
var validTxs []*Transaction
totalUsedGas := big.NewInt(0)
for _, tx := range txs {
sm.ApplyTransaction(state, block, tx)
usedGas, err := sm.ApplyTransaction(state, block, tx)
if err != nil {
ethutil.Config.Log.Infoln(err)
continue
}
accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas))
receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}
receipts = append(receipts, receipt)
validTxs = append(validTxs, tx)
}
return receipts, txs
}
func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error {
// If there's no recipient, it's a contract
// Check if this is a contract creation traction and if so
// create a contract of this tx.
if tx.IsContract() {
err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) {
/*
Applies transactions to the given state and creates new
state objects where needed.
If said objects needs to be created
run the initialization script provided by the transaction and
assume there's a return value. The return value will be set to
the script section of the state object.
*/
totalGasUsed := big.NewInt(0)
// Apply the transaction to the current state
err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false)
if tx.CreatesContract() {
if err == nil {
contract := sm.MakeContract(state, tx)
// Create a new state object and the transaction
// as it's data provider.
contract := sm.MakeStateObject(state, tx)
if contract != nil {
sm.EvalScript(state, contract.Init(), contract, tx, block)
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
script, err := sm.EvalScript(state, contract.Init(), contract, tx, block)
if err != nil {
return nil, fmt.Errorf("[STATE] Error during init script run %v", err)
}
contract.script = script
state.UpdateStateObject(contract)
} else {
return fmt.Errorf("[STATE] Unable to create contract")
return nil, fmt.Errorf("[STATE] Unable to create contract")
}
} else {
return fmt.Errorf("[STATE] contract create:", err)
return nil, fmt.Errorf("[STATE] contract creation tx:", err)
}
} else {
err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
contract := state.GetStateObject(tx.Recipient)
if err == nil && contract != nil && len(contract.Script()) > 0 {
sm.EvalScript(state, contract.Script(), contract, tx, block)
// Find the state object at the "recipient" address. If
// there's an object attempt to run the script.
stateObject := state.GetStateObject(tx.Recipient)
if err == nil && stateObject != nil && len(stateObject.Script()) > 0 {
sm.EvalScript(state, stateObject.Script(), stateObject, tx, block)
} else if err != nil {
return fmt.Errorf("[STATE] process:", err)
return nil, fmt.Errorf("[STATE] process:", err)
}
}
return nil
return totalGasUsed, nil
}
func (sm *StateManager) Process(block *Block, dontReact bool) error {
@ -276,6 +310,14 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
for i := 0; i < uncleLength; i++ {
base.Add(base, UncleInclusionReward)
}
lastCumulGasUsed := big.NewInt(0)
for _, r := range block.Receipts() {
usedGas := new(big.Int).Sub(r.CumulativeGasUsed, lastCumulGasUsed)
usedGas.Add(usedGas, r.Tx.GasPrice)
base.Add(base, usedGas)
}
return base.Add(base, BlockReward)
}
@ -307,10 +349,10 @@ func (sm *StateManager) Stop() {
sm.bc.Stop()
}
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) {
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) {
account := state.GetAccount(tx.Sender())
err := account.ConvertGas(tx.Gas, tx.GasPrice)
err = account.ConvertGas(tx.Gas, tx.GasPrice)
if err != nil {
ethutil.Config.Log.Debugln(err)
return
@ -327,11 +369,13 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj
Value: tx.Value,
//Price: tx.GasPrice,
})
closure.Call(vm, tx.Data, nil)
ret, err = closure.Call(vm, tx.Data, nil)
// Update the account (refunds)
state.UpdateStateObject(account)
state.UpdateStateObject(object)
return
}
func (sm *StateManager) notifyChanges(state *State) {

View File

@ -28,8 +28,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
value := tx.Value
contract := NewContract(addr, value, ZeroHash256)
contract.script = tx.Data
contract.initScript = tx.Init
contract.initScript = tx.Data
state.UpdateStateObject(contract)
@ -82,12 +81,17 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) {
c.SetAddr(addr, val)
}
func (c *StateObject) GetMem(num *big.Int) *ethutil.Value {
func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value {
nb := ethutil.BigToBytes(num, 256)
return c.Addr(nb)
}
/* DEPRECATED */
func (c *StateObject) GetMem(num *big.Int) *ethutil.Value {
return c.GetStorage(num)
}
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
if int64(len(c.script)-1) < pc.Int64() {
return ethutil.NewValue(0)
@ -146,7 +150,7 @@ func (c *StateObject) RlpEncode() []byte {
if c.state != nil {
root = c.state.trie.Root
} else {
root = ZeroHash256
root = ""
}
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)})

View File

@ -9,7 +9,7 @@ import (
)
func TestSync(t *testing.T) {
ethutil.ReadConfig("", ethutil.LogStd)
ethutil.ReadConfig("", ethutil.LogStd, "")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
@ -28,7 +28,7 @@ func TestSync(t *testing.T) {
}
func TestObjectGet(t *testing.T) {
ethutil.ReadConfig("", ethutil.LogStd)
ethutil.ReadConfig("", ethutil.LogStd, "")
db, _ := ethdb.NewMemDatabase()
ethutil.Config.Db = db

31
ethchain/state_test.go Normal file
View File

@ -0,0 +1,31 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"testing"
)
func TestSnapshot(t *testing.T) {
ethutil.ReadConfig("", ethutil.LogStd, "")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256)
state.UpdateStateObject(stateObject)
stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42))
snapshot := state.Snapshot()
stateObject = state.GetStateObject([]byte("aa"))
stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43))
state.Revert(snapshot)
stateObject = state.GetStateObject([]byte("aa"))
if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) {
t.Error("Expected storage 0 to be 42")
}
}

View File

@ -1,6 +1,7 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
"math/big"
@ -15,7 +16,6 @@ type Transaction struct {
Gas *big.Int
GasPrice *big.Int
Data []byte
Init []byte
v byte
r, s []byte
@ -23,8 +23,8 @@ type Transaction struct {
contractCreation bool
}
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction {
return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true}
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction {
return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true}
}
func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction {
@ -46,19 +46,26 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
}
func (tx *Transaction) Hash() []byte {
data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data}
data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
if tx.contractCreation {
data = append(data, tx.Init)
}
/*
if tx.contractCreation {
data = append(data, tx.Init)
}
*/
return ethutil.Sha3Bin(ethutil.NewValue(data).Encode())
}
func (tx *Transaction) IsContract() bool {
func (tx *Transaction) CreatesContract() bool {
return tx.contractCreation
}
/* Depricated */
func (tx *Transaction) IsContract() bool {
return tx.CreatesContract()
}
func (tx *Transaction) CreationAddress() []byte {
return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:]
}
@ -112,10 +119,6 @@ func (tx *Transaction) Sign(privk []byte) error {
func (tx *Transaction) RlpData() interface{} {
data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
if tx.contractCreation {
data = append(data, tx.Init)
}
return append(data, tx.v, tx.r, tx.s)
}
@ -138,18 +141,90 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
tx.Recipient = decoder.Get(3).Bytes()
tx.Value = decoder.Get(4).BigInt()
tx.Data = decoder.Get(5).Bytes()
// If the list is of length 10 it's a contract creation tx
if decoder.Len() == 10 {
tx.v = byte(decoder.Get(6).Uint())
tx.r = decoder.Get(7).Bytes()
tx.s = decoder.Get(8).Bytes()
if len(tx.Recipient) == 0 {
tx.contractCreation = true
tx.Init = decoder.Get(6).Bytes()
tx.v = byte(decoder.Get(7).Uint())
tx.r = decoder.Get(8).Bytes()
tx.s = decoder.Get(9).Bytes()
} else {
tx.v = byte(decoder.Get(6).Uint())
tx.r = decoder.Get(7).Bytes()
tx.s = decoder.Get(8).Bytes()
}
/*
// If the list is of length 10 it's a contract creation tx
if decoder.Len() == 10 {
tx.contractCreation = true
tx.Init = decoder.Get(6).Bytes()
tx.v = byte(decoder.Get(7).Uint())
tx.r = decoder.Get(8).Bytes()
tx.s = decoder.Get(9).Bytes()
} else {
tx.v = byte(decoder.Get(6).Uint())
tx.r = decoder.Get(7).Bytes()
tx.s = decoder.Get(8).Bytes()
}
*/
}
func (tx *Transaction) String() string {
return fmt.Sprintf(`
TX(%x)
Contract: %v
From: %x
To: %x
Nonce: %v
GasPrice: %v
Gas: %v
Value: %v
Data: 0x%x
V: 0x%x
R: 0x%x
S: 0x%x
`,
tx.Hash(),
len(tx.Recipient) == 0,
tx.Sender(),
tx.Recipient,
tx.Nonce,
tx.GasPrice,
tx.Gas,
tx.Value,
tx.Data,
tx.v,
tx.r,
tx.s)
}
type Receipt struct {
Tx *Transaction
PostState []byte
CumulativeGasUsed *big.Int
}
func NewRecieptFromValue(val *ethutil.Value) *Receipt {
r := &Receipt{}
r.RlpValueDecode(val)
return r
}
func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) {
self.Tx = NewTransactionFromValue(decoder.Get(0))
self.PostState = decoder.Get(1).Bytes()
self.CumulativeGasUsed = decoder.Get(2).BigInt()
}
func (self *Receipt) RlpData() interface{} {
return []interface{}{self.Tx.RlpData(), self.PostState, self.CumulativeGasUsed}
}
func (self *Receipt) String() string {
return fmt.Sprintf(`
R
Tx:[ %v]
PostState: 0x%x
CumulativeGasUsed: %v
`,
self.Tx,
self.PostState,
self.CumulativeGasUsed)
}

View File

@ -91,15 +91,15 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
// Process transaction validates the Tx and processes funds from the
// sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) {
func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) {
defer func() {
if r := recover(); r != nil {
log.Println(r)
ethutil.Config.Log.Infoln(r)
err = fmt.Errorf("%v", r)
}
}()
// Get the sender
sender := block.state.GetAccount(tx.Sender())
sender := state.GetAccount(tx.Sender())
if sender.Nonce != tx.Nonce {
return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce)
@ -107,19 +107,21 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
//totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice))
if sender.Amount.Cmp(totAmount) < 0 {
return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
}
//fmt.Println(tx)
// Get the receiver
receiver := block.state.GetAccount(tx.Recipient)
receiver := state.GetAccount(tx.Recipient)
sender.Nonce += 1
// Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
// Subtract the fee
sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice))
} else {
// Subtract the amount from the senders account
sender.SubAmount(totAmount)
@ -127,10 +129,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract
// Add the amount to receivers account which should conclude this transaction
receiver.AddAmount(tx.Value)
block.state.UpdateStateObject(receiver)
state.UpdateStateObject(receiver)
}
block.state.UpdateStateObject(sender)
state.UpdateStateObject(sender)
ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash())

View File

@ -322,3 +322,10 @@ func IsOpCode(s string) bool {
}
return false
}
func AppendScript(init, script []byte) []byte {
s := append(init, byte(oRETURN))
s = append(s, script...)
return s
}

View File

@ -18,6 +18,7 @@ var (
GasCreate = big.NewInt(100)
GasCall = big.NewInt(20)
GasMemory = big.NewInt(1)
GasTx = big.NewInt(500)
)
func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int {
@ -425,6 +426,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
value := stack.Pop()
size, offset := stack.Popn()
// Snapshot the current stack so we are able to
// revert back to it later.
snapshot := vm.state.Snapshot()
// Generate a new address
addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N())
// Create a new contract
@ -447,6 +452,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
closure.Script, err = closure.Call(vm, nil, hook)
if err != nil {
stack.Push(ethutil.BigFalse)
// Revert the state as it was before.
vm.state.Revert(snapshot)
} else {
stack.Push(ethutil.BigD(addr))
@ -472,6 +480,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
snapshot := vm.state.Snapshot()
// Fetch the contract which will serve as the closure body
contract := vm.state.GetStateObject(addr.Bytes())
@ -494,14 +504,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
if err != nil {
stack.Push(ethutil.BigFalse)
// Reset the changes applied this object
//contract.State().Reset()
vm.state.Revert(snapshot)
} else {
stack.Push(ethutil.BigTrue)
vm.state.UpdateStateObject(contract)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
}
vm.state.UpdateStateObject(contract)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
} else {
ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes())
stack.Push(ethutil.BigFalse)

View File

@ -1,6 +1,5 @@
package ethchain
/*
import (
_ "bytes"
"fmt"
@ -13,60 +12,33 @@ import (
)
func TestRun4(t *testing.T) {
ethutil.ReadConfig("", ethutil.LogStd)
ethutil.ReadConfig("", ethutil.LogStd, "")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script, err := mutan.Compile(strings.NewReader(`
int32 a = 10
int32 b = 20
if a > b {
int32 c = this.caller()
}
exit()
`), false)
tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil)
tx.Sign(ContractAddr)
addr := tx.CreationAddress()
contract := MakeContract(tx, state)
state.UpdateStateObject(contract)
fmt.Printf("%x\n", addr)
callerScript, err := mutan.Compile(strings.NewReader(`
// Check if there's any cash in the initial store
if this.store[1000] == 0 {
this.store[1000] = 10**20
}
this.store[1001] = this.value() * 20
this.store[this.origin()] = this.store[this.origin()] + 1000
if this.store[1001] > 20 {
this.store[1001] = 10^50
}
int8 ret = 0
int8 arg = 10
call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret)
big t
for int8 i = 0; i < 10; i++ {
t = i
}
if 10 > 20 {
int8 shouldnt = 2
} else {
int8 should = 1
this.store[this.origin()] = 10**20
hello := "world"
return lambda {
big to = this.data[0]
big from = this.origin()
big value = this.data[1]
if this.store[from] >= value {
this.store[from] = this.store[from] - value
this.store[to] = this.store[to] + value
}
}
`), false)
if err != nil {
fmt.Println(err)
}
fmt.Println(Disassemble(callerScript))
callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil)
callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript)
callerTx.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
// Contract addr as test address
gas := big.NewInt(1000)
@ -79,7 +51,7 @@ func TestRun4(t *testing.T) {
fmt.Println(err)
}
fmt.Println("account.Amount =", account.Amount)
callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice)
callerClosure := NewClosure(account, c, callerScript, state, gas, gasPrice)
vm := NewVm(state, nil, RuntimeVars{
Origin: account.Address(),
@ -89,10 +61,10 @@ func TestRun4(t *testing.T) {
Time: 1,
Diff: big.NewInt(256),
})
_, e = callerClosure.Call(vm, nil, nil)
var ret []byte
ret, e = callerClosure.Call(vm, nil, nil)
if e != nil {
fmt.Println("error", e)
}
fmt.Println("account.Amount =", account.Amount)
fmt.Println(ret)
}
*/

View File

@ -48,7 +48,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
// Insert initial TXs in our little miner 'pool'
miner.txs = ethereum.TxPool().Flush()
miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
miner.block = ethereum.BlockChain().NewBlock(miner.coinbase)
return miner
}
@ -86,7 +86,7 @@ out:
miner.txs = newtxs
// Setup a fresh state to mine on
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
//miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
} else {
if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
@ -125,7 +125,7 @@ func (self *Miner) Stop() {
func (self *Miner) mineNewBlock() {
stateManager := self.ethereum.StateManager()
self.block = self.ethereum.BlockChain().NewBlock(self.coinbase, self.txs)
self.block = self.ethereum.BlockChain().NewBlock(self.coinbase)
// Apply uncles
if len(self.uncles) > 0 {
@ -133,15 +133,10 @@ func (self *Miner) mineNewBlock() {
}
// Accumulate all valid transaction and apply them to the new state
var txs []*ethchain.Transaction
for _, tx := range self.txs {
if err := stateManager.ApplyTransaction(self.block.State(), self.block, tx); err == nil {
txs = append(txs, tx)
}
}
receipts, txs := stateManager.ApplyTransactions(self.block.State(), self.block, self.txs)
self.txs = txs
// Set the transactions to the block so the new SHA3 can be calculated
self.block.SetTransactions(self.txs)
self.block.SetReceipts(receipts, txs)
// Accumulate the rewards included for this block
stateManager.AccumelateRewards(self.block.State(), self.block)

View File

@ -87,14 +87,14 @@ func (lib *PEthereum) SecretToAddress(key string) string {
}
func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) {
return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "")
return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr)
}
func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) (*PReceipt, error) {
return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, initStr, bodyStr)
func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) (*PReceipt, error) {
return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script)
}
func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, initStr, scriptStr string) (*PReceipt, error) {
func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) {
var hash []byte
var contractCreation bool
if len(recipient) == 0 {
@ -121,33 +121,47 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in
var tx *ethchain.Transaction
// Compile and assemble the given data
if contractCreation {
var initScript, mainScript []byte
/*
var initScript, mainScript []byte
var err error
if ethutil.IsHex(initStr) {
initScript = ethutil.FromHex(initStr[2:])
} else {
initScript, err = ethutil.Compile(initStr)
if err != nil {
return nil, err
}
}
if ethutil.IsHex(scriptStr) {
mainScript = ethutil.FromHex(scriptStr[2:])
} else {
mainScript, err = ethutil.Compile(scriptStr)
if err != nil {
return nil, err
}
}
script := ethchain.AppendScript(initScript, mainScript)
*/
var script []byte
var err error
if ethutil.IsHex(initStr) {
initScript = ethutil.FromHex(initStr[2:])
} else {
initScript, err = ethutil.Compile(initStr)
if err != nil {
return nil, err
}
}
if ethutil.IsHex(scriptStr) {
mainScript = ethutil.FromHex(scriptStr[2:])
script = ethutil.FromHex(scriptStr)
} else {
mainScript, err = ethutil.Compile(scriptStr)
script, err = ethutil.Compile(scriptStr)
if err != nil {
return nil, err
}
}
tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript)
tx = ethchain.NewContractCreationTx(value, gas, gasPrice, script)
} else {
// Just in case it was submitted as a 0x prefixed string
if len(initStr) > 0 && initStr[0:2] == "0x" {
initStr = initStr[2:len(initStr)]
if len(scriptStr) > 0 && scriptStr[0:2] == "0x" {
scriptStr = scriptStr[2:len(scriptStr)]
}
tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr))
tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(scriptStr))
}
acc := lib.stateManager.TransState().GetStateObject(keyPair.Address())

View File

@ -31,7 +31,18 @@ func (self *PBlock) ToString() string {
return ""
}
func (self *PBlock) GetTransaction(hash string) *PTx {
tx := self.ref.GetTransaction(ethutil.FromHex(hash))
if tx == nil {
return nil
}
return NewPTx(tx)
}
type PTx struct {
ref *ethchain.Transaction
Value, Hash, Address string
Contract bool
}
@ -41,7 +52,11 @@ func NewPTx(tx *ethchain.Transaction) *PTx {
sender := hex.EncodeToString(tx.Recipient)
isContract := len(tx.Data) > 0
return &PTx{Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract}
return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract}
}
func (self *PTx) ToString() string {
return self.ref.String()
}
type PKey struct {

View File

@ -137,7 +137,7 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error {
if err != nil {
return err
}
result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Init, args.Body)
result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Body)
*reply = NewSuccessRes(result)
return nil
}

View File

@ -19,6 +19,7 @@ type config struct {
Ver string
ClientString string
Pubkey []byte
Identifier string
}
var Config *config
@ -26,7 +27,7 @@ var Config *config
// Read config
//
// Initialize the global Config variable with default settings
func ReadConfig(base string, logTypes LoggerType) *config {
func ReadConfig(base string, logTypes LoggerType, id string) *config {
if Config == nil {
usr, _ := user.Current()
path := path.Join(usr.HomeDir, base)
@ -42,7 +43,8 @@ func ReadConfig(base string, logTypes LoggerType) *config {
}
}
Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"}
Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC9"}
Config.Identifier = id
Config.Log = NewLogger(logTypes, LogLevelDebug)
Config.SetClientString("/Ethereum(G)")
}
@ -53,7 +55,11 @@ func ReadConfig(base string, logTypes LoggerType) *config {
// Set client string
//
func (c *config) SetClientString(str string) {
Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS)
id := runtime.GOOS
if len(c.Identifier) > 0 {
id = c.Identifier
}
Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id)
}
type LoggerType byte

View File

@ -1,7 +1,7 @@
package ethutil
import (
_ "fmt"
"fmt"
"reflect"
"testing"
)
@ -26,7 +26,6 @@ func (db *MemDatabase) Delete(key []byte) error {
delete(db.db, string(key))
return nil
}
func (db *MemDatabase) GetKeys() []*Key { return nil }
func (db *MemDatabase) Print() {}
func (db *MemDatabase) Close() {}
func (db *MemDatabase) LastKnownTD() []byte { return nil }
@ -171,3 +170,17 @@ func TestTrieIterator(t *testing.T) {
t.Errorf("Expected cached nodes to be deleted")
}
}
func TestHashes(t *testing.T) {
_, trie := New()
trie.Update("cat", "dog")
trie.Update("ca", "dude")
trie.Update("doge", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ")
trie.Update("dog", "test")
trie.Update("test", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ")
fmt.Printf("%x\n", trie.Root)
trie.Delete("dog")
fmt.Printf("%x\n", trie.Root)
trie.Delete("test")
fmt.Printf("%x\n", trie.Root)
}

View File

@ -16,7 +16,7 @@ type Value struct {
}
func (val *Value) String() string {
return fmt.Sprintf("%q", val.Val)
return fmt.Sprintf("%x", val.Val)
}
func NewValue(val interface{}) *Value {

28
peer.go
View File

@ -18,7 +18,7 @@ const (
// The size of the output buffer for writing messages
outputBufferSize = 50
// Current protocol version
ProtocolVersion = 12
ProtocolVersion = 17
)
type DiscReason byte
@ -119,7 +119,7 @@ type Peer struct {
// this to prevent receiving false peers.
requestedPeerList bool
host []interface{}
host []byte
port uint16
caps Caps
@ -134,8 +134,7 @@ type Peer struct {
}
func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer {
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes()
pubkey := ethutil.GetKeyRing().Get(0).PublicKey[1:]
return &Peer{
outputQueue: make(chan *ethwire.Msg, outputBufferSize),
@ -342,6 +341,7 @@ func (p *Peer) HandleInbound() {
if ethutil.Config.Debug {
ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash())
ethutil.Config.Log.Infof("[PEER] %v\n", err)
ethutil.Config.Log.Debugln(block)
}
break
} else {
@ -437,7 +437,7 @@ func (p *Peer) HandleInbound() {
// If a parent is found send back a reply
if parent != nil {
ethutil.Config.Log.Debugf("[PEER] Found conical block, returning chain from: %x ", parent.Hash())
ethutil.Config.Log.Debugf("[PEER] Found canonical block, returning chain from: %x ", parent.Hash())
chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks)
if len(chain) > 0 {
ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash())
@ -531,11 +531,10 @@ func (p *Peer) Stop() {
}
func (p *Peer) pushHandshake() error {
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes()
pubkey := ethutil.GetKeyRing().Get(0).PublicKey
msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey,
uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey[1:],
})
p.QueueMessage(msg)
@ -667,23 +666,24 @@ func (p *Peer) RlpData() []interface{} {
return []interface{}{p.host, p.port, p.pubkey}
}
func packAddr(address, port string) ([]interface{}, uint16) {
func packAddr(address, port string) ([]byte, uint16) {
addr := strings.Split(address, ".")
a, _ := strconv.Atoi(addr[0])
b, _ := strconv.Atoi(addr[1])
c, _ := strconv.Atoi(addr[2])
d, _ := strconv.Atoi(addr[3])
host := []interface{}{int32(a), int32(b), int32(c), int32(d)}
host := []byte{byte(a), byte(b), byte(c), byte(d)}
prt, _ := strconv.Atoi(port)
return host, uint16(prt)
}
func unpackAddr(value *ethutil.Value, p uint64) string {
a := strconv.Itoa(int(value.Get(0).Uint()))
b := strconv.Itoa(int(value.Get(1).Uint()))
c := strconv.Itoa(int(value.Get(2).Uint()))
d := strconv.Itoa(int(value.Get(3).Uint()))
byts := value.Bytes()
a := strconv.Itoa(int(byts[0]))
b := strconv.Itoa(int(byts[1]))
c := strconv.Itoa(int(byts[2]))
d := strconv.Itoa(int(byts[3]))
host := strings.Join([]string{a, b, c, d}, ".")
port := strconv.Itoa(int(p))