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,35 +334,43 @@ 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) + + 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") + } + + uncleParent := sm.bc.GetBlock(uncle.PrevHash) + if uncleParent == nil { + return UncleError("Uncle's parent unknown") + } + + if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 { + return UncleError("Uncle too old") + } + + 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)) + + uncleAccount := state.GetAccount(uncle.Coinbase) + uncleAccount.AddAmount(r) + + reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) } - return base.Add(base, BlockReward) -} - -func CalculateUncleReward(block *Block) *big.Int { - return UncleReward -} - -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))) - - addr := make([]byte, len(block.Coinbase)) - copy(addr, block.Coinbase) - state.UpdateStateObject(account) - - for _, uncle := range block.Uncles { - uncleAccount := state.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(CalculateUncleReward(uncle)) - - state.UpdateStateObject(uncleAccount) - } + 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, ðstate.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)