From 2f614900e82036e3e8f6f6a714efc43e09aca830 Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Mon, 15 Sep 2014 01:11:01 +0200
Subject: [PATCH] Updated GHOST

---
 ethchain/block.go         | 13 ++++++-
 ethchain/block_chain.go   |  2 +-
 ethchain/error.go         | 18 ++++++++++
 ethchain/state_manager.go | 73 +++++++++++++++++----------------------
 ethminer/miner.go         |  2 +-
 ethvm/vm.go               | 57 +++++++++++++++++++-----------
 peer.go                   |  2 +-
 7 files changed, 101 insertions(+), 66 deletions(-)

diff --git a/ethchain/block.go b/ethchain/block.go
index d2d012e55..fde6ff04a 100644
--- a/ethchain/block.go
+++ b/ethchain/block.go
@@ -31,11 +31,22 @@ func (bi *BlockInfo) RlpEncode() []byte {
 	return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
 }
 
+type Blocks []*Block
+
+func (self Blocks) AsSet() ethutil.UniqueSet {
+	set := make(ethutil.UniqueSet)
+	for _, block := range self {
+		set.Insert(block.Hash())
+	}
+
+	return set
+}
+
 type Block struct {
 	// Hash to the previous block
 	PrevHash []byte
 	// Uncles of this block
-	Uncles   []*Block
+	Uncles   Blocks
 	UncleSha []byte
 	// The coin base address
 	Coinbase []byte
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go
index 74f47aa90..2d88a0f53 100644
--- a/ethchain/block_chain.go
+++ b/ethchain/block_chain.go
@@ -60,7 +60,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
 
 	if bc.CurrentBlock != nil {
 		var mul *big.Int
-		if block.Time < lastBlockTime+42 {
+		if block.Time < lastBlockTime+5 {
 			mul = big.NewInt(1)
 		} else {
 			mul = big.NewInt(-1)
diff --git a/ethchain/error.go b/ethchain/error.go
index 2cf09a1ec..82949141a 100644
--- a/ethchain/error.go
+++ b/ethchain/error.go
@@ -25,6 +25,24 @@ func IsParentErr(err error) bool {
 	return ok
 }
 
+type UncleErr struct {
+	Message string
+}
+
+func (err *UncleErr) Error() string {
+	return err.Message
+}
+
+func UncleError(str string) error {
+	return &UncleErr{Message: str}
+}
+
+func IsUncleErr(err error) bool {
+	_, ok := err.(*UncleErr)
+
+	return ok
+}
+
 // Block validation error. If any validation fails, this error will be thrown
 type ValidationErr struct {
 	Message string
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 33af259cf..a165ed79d 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -219,7 +219,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
 
 	// I'm not sure, but I don't know if there should be thrown
 	// any errors at this time.
-	if err = sm.AccumelateRewards(state, block); err != nil {
+	if err = sm.AccumelateRewards(state, block, parent); err != nil {
 		statelogger.Errorln("Error accumulating reward", err)
 		return err
 	}
@@ -334,36 +334,44 @@ func (sm *StateManager) ValidateBlock(block *Block) error {
 	return nil
 }
 
-func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
-	base := new(big.Int)
-	for i := 0; i < uncleLength; i++ {
-		base.Add(base, UncleInclusionReward)
-	}
+func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error {
+	reward := new(big.Int)
 
-	return base.Add(base, BlockReward)
-}
+	knownUncles := ethutil.Set(parent.Uncles)
+	nonces := ethutil.NewSet(block.Nonce)
+	for _, uncle := range block.Uncles {
+		if nonces.Include(uncle.Nonce) {
+			// Error not unique
+			return UncleError("Uncle not unique")
+		}
 
-func CalculateUncleReward(block *Block) *big.Int {
-	return UncleReward
-}
+		uncleParent := sm.bc.GetBlock(uncle.PrevHash)
+		if uncleParent == nil {
+			return UncleError("Uncle's parent unknown")
+		}
 
-func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error {
-	// Get the account associated with the coinbase
-	account := state.GetAccount(block.Coinbase)
-	// Reward amount of ether to the coinbase address
-	account.AddAmount(CalculateBlockReward(block, len(block.Uncles)))
+		if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {
+			return UncleError("Uncle too old")
+		}
 
-	addr := make([]byte, len(block.Coinbase))
-	copy(addr, block.Coinbase)
-	state.UpdateStateObject(account)
+		if knownUncles.Include(uncle.Hash()) {
+			return UncleError("Uncle in chain")
+		}
+
+		r := new(big.Int)
+		r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
 
-	for _, uncle := range block.Uncles {
 		uncleAccount := state.GetAccount(uncle.Coinbase)
-		uncleAccount.AddAmount(CalculateUncleReward(uncle))
+		uncleAccount.AddAmount(r)
 
-		state.UpdateStateObject(uncleAccount)
+		reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
 	}
 
+	// Get the account associated with the coinbase
+	account := state.GetAccount(block.Coinbase)
+	// Reward amount of ether to the coinbase address
+	account.AddAmount(reward)
+
 	return nil
 }
 
@@ -375,14 +383,6 @@ func (sm *StateManager) Stop() {
 func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter {
 	bloomf := NewBloomFilter(nil)
 
-	/*
-		for addr, stateObject := range state.Manifest().ObjectChanges {
-			// Set the bloom filter's bin
-			bloomf.Set([]byte(addr))
-
-			sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
-		}
-	*/
 	for _, msg := range state.Manifest().Messages {
 		bloomf.Set(msg.To)
 		bloomf.Set(msg.From)
@@ -390,17 +390,6 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter {
 
 	sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages)
 
-	/*
-		for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges {
-			for addr, value := range mappedObjects {
-				// Set the bloom filter's bin
-				bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr)))
-
-				sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &ethstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value})
-			}
-		}
-	*/
-
 	return bloomf
 }
 
@@ -420,7 +409,7 @@ func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message,
 
 	sm.ApplyDiff(state, parent, block)
 
-	sm.AccumelateRewards(state, block)
+	sm.AccumelateRewards(state, block, parent)
 
 	return state.Manifest().Messages, nil
 }
diff --git a/ethminer/miner.go b/ethminer/miner.go
index 799db79f1..083d9ecde 100644
--- a/ethminer/miner.go
+++ b/ethminer/miner.go
@@ -187,7 +187,7 @@ func (self *Miner) mineNewBlock() {
 	self.block.SetReceipts(receipts, txs)
 
 	// Accumulate the rewards included for this block
-	stateManager.AccumelateRewards(self.block.State(), self.block)
+	stateManager.AccumelateRewards(self.block.State(), self.block, parent)
 
 	self.block.State().Update()
 
diff --git a/ethvm/vm.go b/ethvm/vm.go
index fba8c4a0e..2c516f4f8 100644
--- a/ethvm/vm.go
+++ b/ethvm/vm.go
@@ -3,7 +3,6 @@ package ethvm
 import (
 	"container/list"
 	"fmt"
-	"math"
 	"math/big"
 
 	"github.com/ethereum/eth-go/ethcrypto"
@@ -67,6 +66,19 @@ func New(env Environment) *Vm {
 	return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()}
 }
 
+func calcMemSize(off, l *big.Int) *big.Int {
+	if l.Cmp(ethutil.Big0) == 0 {
+		return ethutil.Big0
+	}
+
+	return new(big.Int).Add(off, l)
+}
+
+// Simple helper
+func u256(n int64) *big.Int {
+	return big.NewInt(n)
+}
+
 func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
 	if self.Recoverable {
 		// Recover from any require exception
@@ -147,7 +159,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
 
 		addStepGasUsage(GasStep)
 
-		var newMemSize uint64 = 0
+		var newMemSize *big.Int = ethutil.Big0
 		switch op {
 		case STOP:
 			gas.Set(ethutil.Big0)
@@ -171,57 +183,62 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
 			gas.Set(GasBalance)
 		case MSTORE:
 			require(2)
-			newMemSize = stack.Peek().Uint64() + 32
+			newMemSize = calcMemSize(stack.Peek(), u256(32))
 		case MLOAD:
 			require(1)
 
-			newMemSize = stack.Peek().Uint64() + 32
+			newMemSize = calcMemSize(stack.Peek(), u256(32))
 		case MSTORE8:
 			require(2)
-			newMemSize = stack.Peek().Uint64() + 1
+			newMemSize = calcMemSize(stack.Peek(), u256(1))
 		case RETURN:
 			require(2)
 
-			newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64()
+			newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
 		case SHA3:
 			require(2)
 
 			gas.Set(GasSha)
 
-			newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64()
+			newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
 		case CALLDATACOPY:
 			require(3)
 
-			newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
+			newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
 		case CODECOPY:
 			require(3)
 
-			newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
+			newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
 		case EXTCODECOPY:
 			require(4)
 
-			newMemSize = stack.data[stack.Len()-1].Uint64() + stack.data[stack.Len()-4].Uint64()
+			newMemSize = calcMemSize(stack.data[stack.Len()-1], stack.data[stack.Len()-4])
 		case CALL, CALLSTATELESS:
 			require(7)
 			gas.Set(GasCall)
 			addStepGasUsage(stack.data[stack.Len()-1])
 
-			x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64()
-			y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64()
+			x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7])
+			y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5])
 
-			newMemSize = uint64(math.Max(float64(x), float64(y)))
+			newMemSize = ethutil.BigMax(x, y)
 		case CREATE:
 			require(3)
 			gas.Set(GasCreate)
 
-			newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64()
+			newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
 		}
 
-		// BUG This will break on overflows. https://github.com/ethereum/eth-go/issues/47
-		newMemSize = (newMemSize + 31) / 32 * 32
-		if newMemSize > uint64(mem.Len()) {
-			m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
-			addStepGasUsage(big.NewInt(int64(m)))
+		if newMemSize.Cmp(ethutil.Big0) > 0 {
+			//newMemSize = (newMemSize + 31) / 32 * 32
+			newMemSize = newMemSize.Add(newMemSize, u256(31)).Div(newMemSize, u256(32)).Mul(newMemSize, u256(32))
+			//if newMemSize > uint64(mem.Len()) {
+			if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
+				newMemSize = newMemSize.Sub(newMemSize, u256(int64(mem.Len())))
+				memGasUsage := newMemSize.Mul(GasMemory, newMemSize).Div(newMemSize, u256(32))
+				//m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
+				addStepGasUsage(memGasUsage)
+			}
 		}
 
 		if !closure.UseGas(gas) {
@@ -235,7 +252,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
 		self.Printf("(pc) %-3d -o- %-14s", pc, op.String())
 		self.Printf(" (g) %-3v (%v)", gas, closure.Gas)
 
-		mem.Resize(newMemSize)
+		mem.Resize(newMemSize.Uint64())
 
 		switch op {
 		case LOG:
diff --git a/peer.go b/peer.go
index 4cc62887c..349d02097 100644
--- a/peer.go
+++ b/peer.go
@@ -675,7 +675,7 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) {
 func (p *Peer) pushHandshake() error {
 	pubkey := p.ethereum.KeyManager().PublicKey()
 	msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
-		P2PVersion, []byte(p.version), []interface{}{"eth"}, uint32(30303) /*p.port*/, pubkey[1:],
+		P2PVersion, []byte(p.version), []interface{}{"eth"}, p.port, pubkey[1:],
 	})
 
 	p.QueueMessage(msg)
-- 
GitLab