Skip to content

Commit 028149d

Browse files
author
Maeda614
committed
add transaction persistance
1 parent a15e313 commit 028149d

6 files changed

Lines changed: 576 additions & 245 deletions

File tree

blockchain/blockchain.go

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"github.com/dgraph-io/badger"
10+
"log"
1011
"os"
1112
"runtime"
1213
)
@@ -98,13 +99,18 @@ func ContinueBlockChain(address string) *BlockChain {
9899
return &chain
99100
}
100101

101-
func (chain *BlockChain) AddBlock(transactions []*Transaction) {
102+
func (chain *BlockChain) AddBlock(transactions []*Transaction) *Block {
102103
var lastHash []byte
103104

105+
for _, tx := range transactions {
106+
if chain.VerifyTransaction(tx) != true {
107+
log.Panic("Invalid Transaction")
108+
}
109+
}
110+
104111
err := chain.Database.View(func(txn *badger.Txn) error {
105112
item, err := txn.Get([]byte("lh"))
106113
Handle(err)
107-
108114
err = item.Value(func(val []byte) error {
109115
lastHash = val
110116
return nil
@@ -126,6 +132,8 @@ func (chain *BlockChain) AddBlock(transactions []*Transaction) {
126132
return err
127133
})
128134
Handle(err)
135+
136+
return newBlock
129137
}
130138

131139
func (chain *BlockChain) Iterator() *ChainIterator {
@@ -155,6 +163,46 @@ func (iter *ChainIterator) Next() *Block {
155163
return block
156164
}
157165

166+
func (chain *BlockChain) FindUTXO() map[string]TxOutputs {
167+
UTXO := make(map[string]TxOutputs)
168+
spentTXOs := make(map[string][]int)
169+
170+
iter := chain.Iterator()
171+
172+
for {
173+
block := iter.Next()
174+
175+
for _, tx := range block.Transactions {
176+
txID := hex.EncodeToString(tx.ID)
177+
178+
Outputs:
179+
for outIdx, out := range tx.Outputs {
180+
if spentTXOs[txID] != nil {
181+
for _, spentOut := range spentTXOs[txID] {
182+
if spentOut == outIdx {
183+
continue Outputs
184+
}
185+
}
186+
}
187+
outs := UTXO[txID]
188+
outs.Outputs = append(outs.Outputs, out)
189+
UTXO[txID] = outs
190+
}
191+
if tx.IsCoinbase() == false {
192+
for _, in := range tx.Inputs {
193+
inTxID := hex.EncodeToString(in.ID)
194+
spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Out)
195+
}
196+
}
197+
}
198+
199+
if len(block.PrevHash) == 0 {
200+
break
201+
}
202+
}
203+
return UTXO
204+
}
205+
158206
func (chain *BlockChain) FindUnspentTransactions(pubKeyHash []byte) []Transaction {
159207
var unspentTxs []Transaction
160208

@@ -181,7 +229,7 @@ func (chain *BlockChain) FindUnspentTransactions(pubKeyHash []byte) []Transactio
181229
unspentTxs = append(unspentTxs, *tx)
182230
}
183231
}
184-
if tx.isCoinbase() == false {
232+
if tx.IsCoinbase() == false {
185233
for _, in := range tx.Inputs {
186234
if in.UsesKey(pubKeyHash) {
187235
inTxID := hex.EncodeToString(in.ID)
@@ -198,20 +246,6 @@ func (chain *BlockChain) FindUnspentTransactions(pubKeyHash []byte) []Transactio
198246
return unspentTxs
199247
}
200248

201-
func (chain *BlockChain) FindUTXO(pubKeyHash []byte) []TxOutput {
202-
var UTXOs []TxOutput
203-
unspentTransactions := chain.FindUnspentTransactions(pubKeyHash)
204-
205-
for _, tx := range unspentTransactions {
206-
for _, out := range tx.Outputs {
207-
if out.IsLockedWithKey(pubKeyHash) {
208-
UTXOs = append(UTXOs, out)
209-
}
210-
}
211-
}
212-
return UTXOs
213-
}
214-
215249
func (chain *BlockChain) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int) {
216250
unspentOuts := make(map[string][]int)
217251
unspentTxs := chain.FindUnspentTransactions(pubKeyHash)
@@ -236,8 +270,8 @@ Work:
236270
return accumulated, unspentOuts
237271
}
238272

239-
func (bc *BlockChain) FindTransaction(ID []byte) (Transaction, error) {
240-
iter := bc.Iterator()
273+
func (chain *BlockChain) FindTransaction(ID []byte) (Transaction, error) {
274+
iter := chain.Iterator()
241275

242276
for {
243277
block := iter.Next()
@@ -256,23 +290,23 @@ func (bc *BlockChain) FindTransaction(ID []byte) (Transaction, error) {
256290
return Transaction{}, errors.New("Transaction does not exist")
257291
}
258292

259-
func (bc *BlockChain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey) {
293+
func (chain *BlockChain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey) {
260294
prevTXs := make(map[string]Transaction)
261295

262296
for _, in := range tx.Inputs {
263-
prevTX, err := bc.FindTransaction(in.ID)
297+
prevTX, err := chain.FindTransaction(in.ID)
264298
Handle(err)
265299
prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
266300
}
267301

268302
tx.Sign(privKey, prevTXs)
269303
}
270304

271-
func (bc *BlockChain) VerifyTransaction(tx *Transaction) bool {
305+
func (chain *BlockChain) VerifyTransaction(tx *Transaction) bool {
272306
prevTXs := make(map[string]Transaction)
273307

274308
for _, in := range tx.Inputs {
275-
prevTX, err := bc.FindTransaction(in.ID)
309+
prevTX, err := chain.FindTransaction(in.ID)
276310
Handle(err)
277311
prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
278312
}

blockchain/transaction.go

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,6 @@ type Transaction struct {
2121
Outputs []TxOutput
2222
}
2323

24-
func (tx Transaction) Serialize() []byte {
25-
var encoded bytes.Buffer
26-
27-
enc := gob.NewEncoder(&encoded)
28-
err := enc.Encode(tx)
29-
30-
if err != nil {
31-
log.Panic(err)
32-
}
33-
34-
return encoded.Bytes()
35-
}
36-
3724
func (tx *Transaction) Hash() []byte {
3825
var hash [32]byte
3926

@@ -45,41 +32,45 @@ func (tx *Transaction) Hash() []byte {
4532
return hash[:]
4633
}
4734

48-
func (tx *Transaction) setID() {
35+
func (tx Transaction) Serialize() []byte {
4936
var encoded bytes.Buffer
50-
var hash [32]byte
5137

52-
encode := gob.NewEncoder(&encoded)
53-
err := encode.Encode(tx)
54-
Handle(err)
38+
enc := gob.NewEncoder(&encoded)
39+
err := enc.Encode(tx)
40+
if err != nil {
41+
log.Panic(err)
42+
}
5543

56-
hash = sha256.Sum256(encoded.Bytes())
57-
tx.ID = hash[:]
44+
return encoded.Bytes()
5845
}
5946

6047
func CoinbaseTx(to, data string) *Transaction {
6148
if data == "" {
62-
data = fmt.Sprint("Coins to %s", to)
49+
randData := make([]byte, 20)
50+
_, err := rand.Read(randData)
51+
Handle(err)
52+
53+
data = fmt.Sprintf("%x", randData)
6354
}
6455

65-
txin := TxInput{[]byte{}, -1, nil,[]byte(data)}
56+
txin := TxInput{[]byte{}, -1, nil, []byte(data)}
6657
txout := NewTXOutput(100, to)
6758

6859
tx := Transaction{nil, []TxInput{txin}, []TxOutput{*txout}}
69-
tx.setID()
60+
tx.ID = tx.Hash()
7061

7162
return &tx
7263
}
7364

74-
func NewTransaction(from, to string, amount int, chain *BlockChain) *Transaction {
65+
func NewTransaction(from, to string, amount int, UTXO *UTXOSet) *Transaction {
7566
var inputs []TxInput
7667
var outputs []TxOutput
7768

7869
wallets, err := wallet.CreateWallets()
7970
Handle(err)
8071
w := wallets.GetWallet(from)
8172
pubKeyHash := wallet.PublicKeyHash(w.PublicKey)
82-
acc, validOutputs := chain.FindSpendableOutputs(pubKeyHash, amount)
73+
acc, validOutputs := UTXO.FindSpendableOutputs(pubKeyHash, amount)
8374

8475
if acc < amount {
8576
log.Panic("Error: not enough funds")
@@ -103,17 +94,17 @@ func NewTransaction(from, to string, amount int, chain *BlockChain) *Transaction
10394

10495
tx := Transaction{nil, inputs, outputs}
10596
tx.ID = tx.Hash()
106-
chain.SignTransaction(&tx, w.PrivateKey)
97+
UTXO.BlockChain.SignTransaction(&tx, w.PrivateKey)
10798

10899
return &tx
109100
}
110101

111-
func (tx *Transaction) isCoinbase() bool {
102+
func (tx *Transaction) IsCoinbase() bool {
112103
return len(tx.Inputs) == 1 && len(tx.Inputs[0].ID) == 0 && tx.Inputs[0].Out == -1
113104
}
114105

115106
func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTXs map[string]Transaction) {
116-
if tx.isCoinbase() {
107+
if tx.IsCoinbase() {
117108
return
118109
}
119110

@@ -142,7 +133,7 @@ func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTXs map[string]Transac
142133
}
143134

144135
func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool {
145-
if tx.isCoinbase() {
136+
if tx.IsCoinbase() {
146137
return true
147138
}
148139

blockchain/tx.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ package blockchain
33
import (
44
"blockchain/main/wallet"
55
"bytes"
6+
"encoding/gob"
67
)
78

89
type TxOutput struct {
910
Value int
1011
PubKeyHash []byte
1112
}
1213

14+
type TxOutputs struct {
15+
Outputs []TxOutput
16+
}
17+
1318
type TxInput struct {
1419
ID []byte
1520
Out int
@@ -37,4 +42,24 @@ func (out *TxOutput) Lock(address []byte) {
3742

3843
func (out *TxOutput) IsLockedWithKey(pubKeyHash []byte) bool {
3944
return bytes.Compare(out.PubKeyHash, pubKeyHash) == 0
45+
}
46+
47+
func (outs TxOutputs) Serialize() []byte {
48+
var buffer bytes.Buffer
49+
50+
encoder := gob.NewEncoder(&buffer)
51+
err := encoder.Encode(outs)
52+
Handle(err)
53+
54+
return buffer.Bytes()
55+
}
56+
57+
func DeserializeOutputs(data []byte) TxOutputs {
58+
var outputs TxOutputs
59+
60+
decoder := gob.NewDecoder(bytes.NewReader(data))
61+
err := decoder.Decode(&outputs)
62+
Handle(err)
63+
64+
return outputs
4065
}

0 commit comments

Comments
 (0)