Working on interop

* Receipts after each transaction
* Fee structure
* Applying fees to miners
This commit is contained in:
obscuren 2014-05-22 17:35:26 +02:00
parent 14787ac148
commit 230aafbf66
11 changed files with 203 additions and 88 deletions

View File

@ -55,6 +55,7 @@ type Block struct {
Nonce []byte
// List of transactions and/or contracts
transactions []*Transaction
receipts []*Receipt
TxSha []byte
}
@ -84,24 +85,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 +112,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 {
@ -172,15 +172,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 +201,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 +226,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 +250,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 +261,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 +306,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 +357,7 @@ func (block *Block) String() string {
Time: %v
Extra: %v
Nonce: %x
NumTx: %v
`,
block.Hash(),
block.PrevHash,
@ -360,5 +372,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

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

View File

@ -97,40 +97,56 @@ 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 {
func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, 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.
totalGasUsed := big.NewInt(0)
if tx.IsContract() {
err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false)
if err == nil {
contract := sm.MakeContract(state, tx)
if contract != nil {
sm.EvalScript(state, contract.Init(), contract, tx, block)
} 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 create:", err)
}
} else {
err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false)
contract := state.GetStateObject(tx.Recipient)
if err == nil && contract != nil && len(contract.Script()) > 0 {
sm.EvalScript(state, contract.Script(), contract, 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 +292,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)
}

View File

@ -146,7 +146,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

@ -1,6 +1,7 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
"math/big"
@ -46,11 +47,13 @@ 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())
}
@ -138,18 +141,87 @@ 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()
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()
/*
// 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()
}
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
Nonce: %v
GasPrice: %v
Gas: %v
To: %x
Value: %v
Data: 0x%x
V: 0x%x
R: 0x%x
S: 0x%x
`,
tx.Hash(),
len(tx.Recipient) > 1,
tx.Sender(),
tx.Nonce,
tx.GasPrice,
tx.Gas,
tx.Recipient,
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

@ -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 {

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

@ -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)
@ -43,6 +44,7 @@ func ReadConfig(base string, logTypes LoggerType) *config {
}
Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"}
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

@ -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 {