aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain/block_chain.go
blob: 5b55782a9eeba84f93ed772cd2762c34502ce281 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package ethchain

import (
    "bytes"
    "github.com/ethereum/eth-go/ethutil"
    "log"
    "math"
    "math/big"
)

type BlockChain struct {
    // The famous, the fabulous Mister GENESIIIIIIS (block)
    genesisBlock *Block
    // Last known total difficulty
    TD *big.Int

    LastBlockNumber uint64

    CurrentBlock  *Block
    LastBlockHash []byte
}

func NewBlockChain() *BlockChain {
    bc := &BlockChain{}
    bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis))

    bc.setLastBlock()

    return bc
}

func (bc *BlockChain) Genesis() *Block {
    return bc.genesisBlock
}

func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
    var root interface{}
    var lastBlockTime int64
    hash := ZeroHash256

    if bc.CurrentBlock != nil {
        root = bc.CurrentBlock.State().Root
        hash = bc.LastBlockHash
        lastBlockTime = bc.CurrentBlock.Time
    }

    block := CreateBlock(
        root,
        hash,
        coinbase,
        ethutil.BigPow(2, 32),
        nil,
        "",
        txs)

    if bc.CurrentBlock != nil {
        var mul *big.Int
        if block.Time < lastBlockTime+42 {
            mul = big.NewInt(1)
        } else {
            mul = big.NewInt(-1)
        }

        diff := new(big.Int)
        diff.Add(diff, bc.CurrentBlock.Difficulty)
        diff.Div(diff, big.NewInt(1024))
        diff.Mul(diff, mul)
        diff.Add(diff, bc.CurrentBlock.Difficulty)
        block.Difficulty = diff
    }

    return block
}

func (bc *BlockChain) HasBlock(hash []byte) bool {
    data, _ := ethutil.Config.Db.Get(hash)
    return len(data) != 0
}

func (bc *BlockChain) GenesisBlock() *Block {
    return bc.genesisBlock
}

// Get chain return blocks from hash up to max in RLP format
func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} {
    var chain []interface{}
    // Get the current hash to start with
    currentHash := bc.CurrentBlock.Hash()
    // Get the last number on the block chain
    lastNumber := bc.BlockInfo(bc.CurrentBlock).Number
    // Get the parents number
    parentNumber := bc.BlockInfoByHash(hash).Number
    // Get the min amount. We might not have max amount of blocks
    count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max)))
    startNumber := parentNumber + count

    num := lastNumber
    for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash {
        num--
    }
    for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ {
        // Get the block of the chain
        block := bc.GetBlock(currentHash)
        currentHash = block.PrevHash

        chain = append(chain, block.Value().Val)

        num--
    }

    return chain
}

func (bc *BlockChain) setLastBlock() {
    data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
    if len(data) != 0 {
        block := NewBlockFromBytes(data)
        info := bc.BlockInfo(block)
        bc.CurrentBlock = block
        bc.LastBlockHash = block.Hash()
        bc.LastBlockNumber = info.Number

        log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber)
    }

    // Set the last know difficulty (might be 0x0 as initial value, Genesis)
    bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
}

func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
    ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes())
    bc.TD = td
}

// Add a block to the chain and record addition information
func (bc *BlockChain) Add(block *Block) {
    bc.writeBlockInfo(block)

    // Prepare the genesis block
    bc.CurrentBlock = block
    bc.LastBlockHash = block.Hash()

    encodedBlock := block.RlpEncode()
    ethutil.Config.Db.Put(block.Hash(), encodedBlock)
    ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
}

func (bc *BlockChain) GetBlock(hash []byte) *Block {
    data, _ := ethutil.Config.Db.Get(hash)

    return NewBlockFromData(data)
}

func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo {
    bi := BlockInfo{}
    data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...))
    bi.RlpDecode(data)

    return bi
}

func (bc *BlockChain) BlockInfo(block *Block) BlockInfo {
    bi := BlockInfo{}
    data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
    bi.RlpDecode(data)

    return bi
}

// Unexported method for writing extra non-essential block info to the db
func (bc *BlockChain) writeBlockInfo(block *Block) {
    bc.LastBlockNumber++
    bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash}

    // For now we use the block hash with the words "info" appended as key
    ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode())
}

func (bc *BlockChain) Stop() {
    if bc.CurrentBlock != nil {
        log.Println("[CHAIN] Stopped")
    }
}