diff --git a/blockchain/block.go b/blockchain/block.go index b552cb4..6bea386 100644 --- a/blockchain/block.go +++ b/blockchain/block.go @@ -4,13 +4,16 @@ import ( "bytes" "encoding/gob" "log" + "time" ) type Block struct { + Timestamp int64 Hash []byte Transactions []*Transaction //burada data vardı sımdı datalar yerını transectıonlara aldı PrevHash []byte Nonce int + Height int } // HashTransactions fonksiyonu, bloğun islemlerini hash eder @@ -26,8 +29,8 @@ func (b *Block) HashTransactions() []byte { } // CreateBlock fonksiyonu, yeni bir bloğu olusturur -func CreateBlock(tsx []*Transaction, prevHash []byte) *Block { - block := &Block{[]byte{}, tsx, prevHash, 0} //[]byte(data) kısmı strıng ıfadeyi byte dizisine donduruyor +func CreateBlock(tsx []*Transaction, prevHash []byte, height int) *Block { + block := &Block{time.Now().Unix(), []byte{}, tsx, prevHash, 0, height} //[]byte(data) kısmı strıng ıfadeyi byte dizisine donduruyor pow := NewProof(block) //yeni bir iş kanıtı olusturuyoruz nonce, hash := pow.Run() //bu işkanıtınını çalıştırıyoruz blogunhasını ve nance degerını eklıyoruz @@ -38,7 +41,7 @@ func CreateBlock(tsx []*Transaction, prevHash []byte) *Block { // Genesis fonksiyonu, ilk bloğu olusturur func Genesis(coinbase *Transaction) *Block { - return CreateBlock([]*Transaction{coinbase}, []byte{}) + return CreateBlock([]*Transaction{coinbase}, []byte{}, 0) } //Badger DB sadece byte kabul ettıgı ıcın serılestırme ve deserilize ıslemlerı kolyalastıralım @@ -62,8 +65,8 @@ func (b *Block) Serialize() []byte { } -// Deserilize fonksiyonu, verilen byte diliminden (data) bir Block struct'ı oluşturur ve döndürür. -func Deserilize(data []byte) *Block { +// Deserialize fonksiyonu, verilen byte diliminden (data) bir Block struct'ı oluşturur ve döndürür. +func Deserialize(data []byte) *Block { var block Block // Block türünde bir değişken oluşturuluyor // bytes.NewReader(data) ile data byte dilimi üzerinde bir okuyucu (reader) oluşturuluyor diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 478e2a7..b174e08 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -9,13 +9,14 @@ import ( "github.com/dgraph-io/badger" "log" "os" + "path/filepath" "runtime" + "strings" ) const ( - dbPath = "./tmp/blocks" - dbFile = "./tmp/blocks/MANIFEST" - genesisData = "First Transection from genesis" + dbPath = "./tmp/blocks_%s" + genesisData = "First Transaction from Genesis" ) type BlockChain struct { //Block zıncırını tutar @@ -23,13 +24,13 @@ type BlockChain struct { //Block zıncırını tutar Database *badger.DB } -type BlockChainIterator struct { //Blockchain üzerinde gezmek ıcın kullanılır - CurrentHash []byte - Database *badger.DB -} +//type BlockChainIterator struct { //Blockchain üzerinde gezmek ıcın kullanılır +// CurrentHash []byte +// Database *badger.DB +//} -func DBexists() bool { //block zıncırın var olup olmadıgını kontrolunu yapıcak - if _, err := os.Stat(dbFile); os.IsNotExist(err) { +func DBexists(path string) bool { //block zıncırın var olup olmadıgını kontrolunu yapıcak + if _, err := os.Stat(path + "/MANIFEST"); os.IsNotExist(err) { return false } return true @@ -41,20 +42,21 @@ Bu fonksiyon, mevcut bir blockchain'in varlığını kontrol eder, varsa veritab ve bu bilgileri kullanarak bir BlockChain yapısı oluşturur. Daha sonra bu yapının işaretçisini döndürür. Bu işlem, mevcut bir blockchain'e devam etmek veya yeni işlemler eklemek için kullanılır. */ -func ContinueBlockChain(address string) *BlockChain { - if DBexists() == false { //veritabaının olup olmadıgını kontrolunu yapar +func ContinueBlockChain(nodeId string) *BlockChain { + path := fmt.Sprintf(dbPath, nodeId) + if DBexists(path) == false { //veritabaının olup olmadıgını kontrolunu yapar fmt.Println("Mevcut bir blockchain bulunamadı, bir tane oluşturun!") runtime.Goexit() } var lastHash []byte - opts := badger.DefaultOptions(dbPath) - opts.Dir = dbPath - opts.ValueDir = dbPath + opts := badger.DefaultOptions(path) + opts.Dir = path + opts.ValueDir = path opts.Logger = nil - db, err := badger.Open(opts) + db, err := openDB(path, opts) Handle(err) err = db.Update(func(txn *badger.Txn) error { @@ -72,22 +74,21 @@ func ContinueBlockChain(address string) *BlockChain { } // InitBlockChain BlockChainin başlatılmasını sağlar -func InitBlockChain(address string) *BlockChain { - - var lastHash []byte +func InitBlockChain(address, nodeId string) *BlockChain { + path := fmt.Sprintf(dbPath, nodeId) - if DBexists() { //verı tabanını var olup olmadıgının kontrolu + if DBexists(path) { //verı tabanını var olup olmadıgının kontrolu fmt.Printf("Blok zinciri zaten mevcut\n") runtime.Goexit() } - + var lastHash []byte //Database baglantısı olusturulur - opts := badger.DefaultOptions(dbPath) - opts.Dir = dbPath - opts.ValueDir = dbPath + opts := badger.DefaultOptions(path) + opts.Dir = path + opts.ValueDir = path opts.Logger = nil - db, err := badger.Open(opts) + db, err := openDB(path, opts) Handle(err) //Databasede bir güncelleme ekleme değişiklik işlemi yapılıcaktır @@ -110,32 +111,72 @@ func InitBlockChain(address string) *BlockChain { } // AddBlock block zincirine blok elememızı saglar -func (chain *BlockChain) AddBlock(transactions []*Transaction) *Block { - var lastHash []byte //lastHash degerini olusturduk +func (chain *BlockChain) AddBlock(block *Block) { + err := chain.Database.Update(func(txn *badger.Txn) error { + if _, err := txn.Get(block.Hash); err == nil { + return nil + } + + blockData := block.Serialize() + err := txn.Set(block.Hash, blockData) + Handle(err) + + item, err := txn.Get([]byte("lh")) + Handle(err) + lastHash, _ := item.ValueCopy(nil) + + item, err = txn.Get(lastHash) + Handle(err) + lastBlockData, _ := item.ValueCopy(nil) + + lastBlock := Deserialize(lastBlockData) + + if block.Height > lastBlock.Height { + err = txn.Set([]byte("lh"), block.Hash) + Handle(err) + chain.LastHash = block.Hash + } - for _, tx := range transactions { //gelen transactionları döndürerek - if chain.VerifyTransaction(tx) != true { //Gelen transactionları kontrol edip - log.Panic("Invalid Transaction") //Hatalı bir transaction varsa hata mesajını verir + return nil + }) + Handle(err) +} + +func (chain *BlockChain) MineBlock(transactions []*Transaction) *Block { + var lastHash []byte + var lastHeight int + + for _, tx := range transactions { + if chain.VerifyTransaction(tx) != true { + log.Panic("Invalid Transaction") } } - err := chain.Database.View(func(txn *badger.Txn) error { //veritabanından son hash degerini alıyoruz - item, err := txn.Get([]byte("lh")) //son hash degerini alıyoruz + err := chain.Database.View(func(txn *badger.Txn) error { + item, err := txn.Get([]byte("lh")) + Handle(err) + lastHash, err = item.ValueCopy(nil) + + item, err = txn.Get(lastHash) Handle(err) - lastHash, err = item.ValueCopy(nil) //son hash degerini alıyoruz + lastBlockData, _ := item.ValueCopy(nil) + + lastBlock := Deserialize(lastBlockData) + + lastHeight = lastBlock.Height return err }) Handle(err) - newBlock := CreateBlock(transactions, lastHash) //yeni blok olusturuyoruz + newBlock := CreateBlock(transactions, lastHash, lastHeight+1) - err = chain.Database.Update(func(txn *badger.Txn) error { //veritabanına yeni blok ekliyoruz - err := txn.Set(newBlock.Hash, newBlock.Serialize()) //yeni blok veritabanına kaydediliyor + err = chain.Database.Update(func(txn *badger.Txn) error { + err := txn.Set(newBlock.Hash, newBlock.Serialize()) Handle(err) - err = txn.Set([]byte("lh"), newBlock.Hash) //son hash degeri veritabanına kaydediliyor + err = txn.Set([]byte("lh"), newBlock.Hash) - chain.LastHash = newBlock.Hash //son hash degeri veritabanına kaydedildi + chain.LastHash = newBlock.Hash return err }) @@ -144,80 +185,64 @@ func (chain *BlockChain) AddBlock(transactions []*Transaction) *Block { return newBlock } -// Iterator :BlockChaın de okuma işlemi yapmak için başlangıç değerlerini atayan kod -func (chain *BlockChain) Iterator() *BlockChainIterator { - iter := &BlockChainIterator{chain.LastHash, chain.Database} - return iter -} +func (chain *BlockChain) GetBestHeight() int { + var lastBlock Block -// Next BlockChaınde gerıye dogru ılerlemeyı saglar ve suankı blogun verılerını gerıye doner -func (iter *BlockChainIterator) Next() *Block { - var block *Block - err := iter.Database.View(func(txn *badger.Txn) error { //database den okum yapıcak - item, err := txn.Get(iter.CurrentHash) //son blogun hası ıle ara son blogun verılerıne erıs + err := chain.Database.View(func(txn *badger.Txn) error { + item, err := txn.Get([]byte("lh")) Handle(err) + lastHash, _ := item.ValueCopy(nil) - encoderBlock, err := item.ValueCopy(nil) //son blogun verıelrını al - block = Deserilize(encoderBlock) //blog verılerını deserılıze et - return err + item, err = txn.Get(lastHash) + Handle(err) + lastBlockData, _ := item.ValueCopy(nil) + + lastBlock = *Deserialize(lastBlockData) + + return nil }) Handle(err) - iter.CurrentHash = block.PrevHash //yenı blog suankının bır oncekı demıs olduk - return block //gerıye su ankı blogu gerı doner + + return lastBlock.Height } -// -//// FindUnspentTransactions : Bu fonksiyon, bir blockchain üzerinde belirli bir adrese gönderilmiş ancak henüz harcanmamış (unspent) işlemleri bulmak için kullanılır. -//func (chain *BlockChain) FindUnspentTransactions(pubKeyHash []byte) []Transaction { -// var unspentTxs []Transaction // Harcanmamış işlemleri tutacak slice -// spentTXOs := make(map[string][]int) // Harcanmış işlemlerin çıktılarını izlemek için kullanılacak map -// -// iter := chain.Iterator() // Blok zinciri iteratorunu olustur -// -// for { -// block := iter.Next() // Sıradaki bloğu al -// -// for _, tx := range block.Transactions { // Bloktaki her işlem için döngü -// txID := hex.EncodeToString(tx.ID) // İşlem ID'sini hex formatına dönüştürerek al -// -// Outputs: -// for outIdx, out := range tx.Outputs { // İşlemin çıktıları üzerinde döngü -// // Eğer bu çıktı daha önce harcanmışsa atla -// if spentTXOs[txID] != nil { -// for _, spentOut := range spentTXOs[txID] { -// if spentOut == outIdx { -// continue Outputs -// } -// } -// } -// -// // Eğer çıktı, belirtilen adrese gönderilmişse -// if out.IsLockedWithKey(pubKeyHash) { //aranan adres tarafından acılıp acılmayacagı kontrol edılır -// unspentTxs = append(unspentTxs, *tx) // Harcanmamış işlemler listesine ekle -// } -// } -// -// // Coinbase işlemi değilse (yani normal bir transfer işlemi) -// if tx.IsCoinbase() == false { -// // İşlemin girdileri üzerinde döngü -// for _, in := range tx.Inputs { -// // Eğer bu girişin kilidi (unlock) belirtilen adrese açılabiliyorsa -// if in.UsesKey(pubKeyHash) { -// inTxID := hex.EncodeToString(in.ID) // Girişin işlem ID'sini alarak hex formatına dönüştür -// spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Out) // Harcanmış işlemler listesine ekle -// } -// } -// } -// } -// -// // Eğer bloğun önceki hash değeri yoksa (genesis block durumu), iterasyonu sonlandır -// if len(block.PrevHash) == 0 { -// break -// } -// } -// -// return unspentTxs // Harcanmamış işlemleri içeren slice'i döndür -//} +func (chain *BlockChain) GetBlock(blockHash []byte) (Block, error) { + var block Block + + err := chain.Database.View(func(txn *badger.Txn) error { + if item, err := txn.Get(blockHash); err != nil { + return errors.New("Block is not found") + } else { + blockData, _ := item.ValueCopy(nil) + + block = *Deserialize(blockData) + } + return nil + }) + if err != nil { + return block, err + } + + return block, nil +} + +func (chain *BlockChain) GetBlockHashes() [][]byte { + var blocks [][]byte + + iter := chain.Iterator() + + for { + block := iter.Next() + + blocks = append(blocks, block.Hash) + + if len(block.PrevHash) == 0 { + break + } + } + + return blocks +} // FindUTXO fonksiyonu, belirtilen bir adrese gönderilmiş ve henüz harcanmamış (UTXO) çıktıları bulmak için kullanılır. func (chain *BlockChain) FindUTXO() map[string]TxOutputs { @@ -316,3 +341,29 @@ func (bc *BlockChain) VerifyTransaction(tx *Transaction) bool { return tx.Verify(prevTXs) // Transaction yapısının geçerliliğini doğrular } + +func retry(dir string, originalOpts badger.Options) (*badger.DB, error) { + lockPath := filepath.Join(dir, "LOCK") + if err := os.Remove(lockPath); err != nil { + return nil, fmt.Errorf(`removing "LOCK": %s`, err) + } + retryOpts := originalOpts + retryOpts.Truncate = true + db, err := badger.Open(retryOpts) + return db, err +} + +func openDB(dir string, opts badger.Options) (*badger.DB, error) { + if db, err := badger.Open(opts); err != nil { + if strings.Contains(err.Error(), "LOCK") { + if db, err := retry(dir, opts); err == nil { + log.Println("database unlocked, value log truncated") + return db, nil + } + log.Println("could not unlock database:", err) + } + return nil, err + } else { + return db, nil + } +} diff --git a/blockchain/chain_iter.go b/blockchain/chain_iter.go new file mode 100644 index 0000000..c603ca6 --- /dev/null +++ b/blockchain/chain_iter.go @@ -0,0 +1,32 @@ +package blockchain + +import "github.com/dgraph-io/badger" + +type BlockChainIterator struct { + CurrentHash []byte + Database *badger.DB +} + +func (chain *BlockChain) Iterator() *BlockChainIterator { + iter := &BlockChainIterator{chain.LastHash, chain.Database} + + return iter +} + +func (iter *BlockChainIterator) Next() *Block { + var block *Block + + err := iter.Database.View(func(txn *badger.Txn) error { + item, err := txn.Get(iter.CurrentHash) + Handle(err) + encodedBlock, err := item.ValueCopy(nil) + block = Deserialize(encodedBlock) + + return err + }) + Handle(err) + + iter.CurrentHash = block.PrevHash + + return block +} diff --git a/blockchain/transaction.go b/blockchain/transaction.go index 1f7f69a..1303eff 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -42,48 +42,48 @@ func CoinbaseTx(to, data string) *Transaction { } // NewTransaction, belirtilen bir adresten başka bir adrese belirtilen miktar token transferi yapacak yeni bir işlem oluşturur. -func NewTransaction(from, to string, amount int, UTXO *UTXOSet) *Transaction { - var inputs []TxInput // Bu işlemdeki girdiler (inputs) - var outputs []TxOutput // Bu işlemdeki çıktılar (outputs) +func NewTransaction(w *wallet.Wallet, to string, amount int, UTXO *UTXOSet) *Transaction { + var inputs []TxInput + var outputs []TxOutput - wallets, err := wallet.CreateWallets() // Cüzdanları oluşturan fonksiyon, cüzdan dosyasını okur - Handle(err) // Hata durumunda işlemi ele alır - - w := wallets.GetWallet(from) // Gönderenin cüzdanını belirtilen adresten alır - pubKeyHash := wallet.PublicKeyHash(w.PublicKey) // Cüzdanın public key hash değerini hesaplar - - // Belirtilen miktarda token transferi için harcanabilir çıktıları bulur + pubKeyHash := wallet.PublicKeyHash(w.PublicKey) acc, validOutputs := UTXO.FindSpendableOutputs(pubKeyHash, amount) - if acc < amount { // Hesaptaki bakiye belirtilen miktarı karşılayamıyorsa - log.Panic("Error: not enough funds") // Hata mesajı verir ve işlemi sonlandırır + if acc < amount { + log.Panic("Error: not enough funds") } - // Harcanabilir çıktıları işleyerek girdi (input) yapısını oluşturur for txid, outs := range validOutputs { - txID, err := hex.DecodeString(txid) // Hexadecimal formatındaki txid'yi byte dizisine dönüştürür - Handle(err) // Hata durumunda işlemi ele alır + txID, err := hex.DecodeString(txid) + Handle(err) for _, out := range outs { - input := TxInput{txID, out, nil, w.PublicKey} // Girdi (input) yapısını oluşturur + input := TxInput{txID, out, nil, w.PublicKey} inputs = append(inputs, input) } } - // Belirtilen miktarda çıktı (output) oluşturur ve çıktı listesine ekler + from := fmt.Sprintf("%s", w.Address()) + outputs = append(outputs, *NewTXOutput(amount, to)) if acc > amount { - // Gönderenin kalan bakiyesi için ek bir çıktı oluşturur ve çıktı listesine ekler outputs = append(outputs, *NewTXOutput(acc-amount, from)) } - // İşlem yapısını oluşturur tx := Transaction{nil, inputs, outputs} - tx.ID = tx.Hash() // İşlemin hash değerini hesaplar - UTXO.Blockchain.SignTransaction(&tx, w.PrivateKey) // İşlemi imzalar + tx.ID = tx.Hash() + UTXO.Blockchain.SignTransaction(&tx, w.PrivateKey) + + return &tx +} +func DeserializeTransaction(data []byte) Transaction { + var transaction Transaction - return &tx // Oluşturulan işlem yapısını döndürür + decoder := gob.NewDecoder(bytes.NewReader(data)) + err := decoder.Decode(&transaction) + Handle(err) + return transaction } /* diff --git a/cli/cli.go b/cli/cli.go index 51c8ccc..f0dea3f 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -4,6 +4,7 @@ import ( "flag" "fmt" "github.com/SadikSunbul/GO-BlockChain-Simulation/blockchain" + "github.com/SadikSunbul/GO-BlockChain-Simulation/network" "github.com/SadikSunbul/GO-BlockChain-Simulation/wallet" "log" "os" @@ -22,22 +23,36 @@ func (cli *CommandLine) printUsage() { fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "getbalance -address ADDRESS", "Belirtilen adrese ait bakiyeyi görüntüler") fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "createblockchain -address ADDRESS", "Yeni bir blok zinciri oluşturur ve belirtilen adrese oluşum ödülünü gönderir") fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "printchain", "Blok zincirindeki tüm blokları yazdırır") - fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "send -from FROM -to TO -amount AMOUNT", "Belirtilen miktarı belirtilen adresten diğer bir adrese gönderir") + fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "send -from FROM -to TO -amount AMOUNT -mine", "Belirli bir miktarda coin gönder. Ardından -mine bayrağı ayarlanır, bu düğüm üzerinde madencilik yap") fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "createwallet", "Yeni bir cüzdan oluşturur") fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "listaddresses", "Cüzdan dosyamızdaki adresleri listeleyin") fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "reindexutxo", "UTXO setini yeniden oluşturur") + fmt.Printf(" \033[35m%-40s : %s\n\033[0m", "startnode -miner ADDRESS", "NODE_ID ortamında belirtilen kimliğe sahip bir düğüm başlatın. var. -miner madenciliği mümkün kılar") } // reindexUTXO fonksiyonu, UTXO setini yeniden oluşturur. -func (cli *CommandLine) reindexUTXO() { - chain := blockchain.ContinueBlockChain("") // blockchain adında bir Blockchain nesnesi - defer chain.Database.Close() // blok zincirini kapat - UTXOSet := blockchain.UTXOSet{chain} // UTXO setini oluştur - UTXOSet.Reindex() // UTXO setini yeniden oluştur - - count := UTXOSet.CountTransactions() // UTXO setindeki işlemleri sayar - fmt.Printf("Done! There are %d transactions in the UTXO set.\n", count) // UTXO setindeki işlemlerin sayısını ekrana yazdırır +func (cli *CommandLine) reindexUTXO(nodeID string) { + chain := blockchain.ContinueBlockChain(nodeID) // blockchain adında bir Blockchain nesnesi + defer chain.Database.Close() // blok zincirini kapat + UTXOSet := blockchain.UTXOSet{chain} // UTXO setini oluştur + UTXOSet.Reindex() // UTXO setini yeniden oluştur + + count := UTXOSet.CountTransactions() // UTXO setindeki işlemleri sayar + fmt.Printf("Tamamlamak! UTXO kümesinde %d işlem var.\n", count) // UTXO setindeki işlemlerin sayısını ekrana yazdırır +} + +func (cli *CommandLine) StartNode(nodeID, minerAddress string) { + fmt.Printf("Başlangıç Düğümü\n %s\n", nodeID) + + if len(minerAddress) > 0 { + if wallet.ValidateAddress(minerAddress) { + fmt.Println("Madencilik açık. Ödülleri alacağınız adres: ", minerAddress) + } else { + log.Panic("Yanlış madenci adresi!") + } + } + network.StartServer(nodeID, minerAddress) } // validateArgs fonksiyonu, komut satırı argümanlarını doğrular. @@ -52,10 +67,10 @@ func (cli *CommandLine) validateArgs() { } // printChain fonksiyonu, blok zincirindeki tüm blokları yazdırır -func (cli *CommandLine) printChain() { - chain := blockchain.ContinueBlockChain("") // blockchain adında bir Blockchain nesnesi - defer chain.Database.Close() // blok zincirini kapat - iter := chain.Iterator() // blok zinciri iteratorunu oluştur +func (cli *CommandLine) printChain(nodeID string) { + chain := blockchain.ContinueBlockChain(nodeID) // blockchain adında bir Blockchain nesnesi + defer chain.Database.Close() // blok zincirini kapat + iter := chain.Iterator() // blok zinciri iteratorunu oluştur fmt.Println() for { // blok zinciri sonuna kadar döngü @@ -79,12 +94,12 @@ func (cli *CommandLine) printChain() { } // createBlockChain fonksiyonu, belirtilen adresin blok zincirini oluşturur -func (cli *CommandLine) createBlockChain(address string) { // blockchain oluşturur +func (cli *CommandLine) createBlockChain(address, nodeID string) { // blockchain oluşturur if !wallet.ValidateAddress(address) { // adresin dogrulugunu kontrol eder log.Panic("\033[31mAddress is not Valid\033[0m") } - chain := blockchain.InitBlockChain(address) // adresin blok zincirini oluşturur - defer chain.Database.Close() // blok zincirini kapat + chain := blockchain.InitBlockChain(address, nodeID) // adresin blok zincirini oluşturur + defer chain.Database.Close() // blok zincirini kapat UTXOSet := blockchain.UTXOSet{chain} // adresin UTXO setini oluşturur UTXOSet.Reindex() // adresin UTXO setini yeniden oluşturur @@ -93,13 +108,13 @@ func (cli *CommandLine) createBlockChain(address string) { // blockchain oluştu } // getBalance fonksiyonu, belirtilen adresin bakiyesini bulur -func (cli *CommandLine) getBalance(address string) { +func (cli *CommandLine) getBalance(address, nodeID string) { if !wallet.ValidateAddress(address) { // adresin dogrulugunu kontrol eder log.Panic("\033[31mAddress is not Valid\033[0m") } - chain := blockchain.ContinueBlockChain(address) // adresin blok zincirini okur - UTXOSet := blockchain.UTXOSet{chain} // adresin UTXO setini oluşturur - defer chain.Database.Close() // blok zincirini kapat + chain := blockchain.ContinueBlockChain(nodeID) // adresin blok zincirini okur + UTXOSet := blockchain.UTXOSet{chain} // adresin UTXO setini oluşturur + defer chain.Database.Close() // blok zincirini kapat balance := 0 pubKeyHash := wallet.Base58Decode([]byte(address)) // adresin base58 kodunu okur @@ -114,44 +129,71 @@ func (cli *CommandLine) getBalance(address string) { } // send fonksiyonu, belirtilen miktarı belirtilen adresten diğer bir adrese gönderir. -func (cli *CommandLine) send(from, to string, amount int) { - if !wallet.ValidateAddress(to) { // gonderilecek adresin dogrulugunu kontrol eder - log.Panic("\033[31mAddress is not Valid\033[0m") // dogrulama hatasını verir +func (cli *CommandLine) send(from, to string, amount int, nodeID string, mineNow bool) { + if !wallet.ValidateAddress(to) { + log.Panic("Address is not Valid") } - if !wallet.ValidateAddress(from) { // gonderen adresin dogrulugunu kontrol eder - log.Panic("\033[31mAddress is not Valid\033[0m") + if !wallet.ValidateAddress(from) { + log.Panic("Address is not Valid") + } + chain := blockchain.ContinueBlockChain(nodeID) + UTXOSet := blockchain.UTXOSet{chain} + defer chain.Database.Close() + + wallets, err := wallet.CreateWallets(nodeID) + if err != nil { + log.Panic(err) + } + wallet := wallets.GetWallet(from) + + tx := blockchain.NewTransaction(&wallet, to, amount, &UTXOSet) + if mineNow { + cbTx := blockchain.CoinbaseTx(from, "") + txs := []*blockchain.Transaction{cbTx, tx} + block := chain.MineBlock(txs) + UTXOSet.Update(block) + } else { + network.SendTx(network.KnownNodes[0], tx) + fmt.Println("send tx") } - chain := blockchain.ContinueBlockChain(from) // gonderenin blok zincirini okur - UTXOSet := blockchain.UTXOSet{chain} // gonderenin UTXO setini oluşturur - defer chain.Database.Close() // blok zincirini kapat - tx := blockchain.NewTransaction(from, to, amount, &UTXOSet) // yeni bir işlem oluşturur - cbTx := blockchain.CoinbaseTx(from, "") //madencının parasını verıcezdrom olan madencı burada - block := chain.AddBlock([]*blockchain.Transaction{cbTx, tx}) // blok zincirine ekler - UTXOSet.Update(block) // UTXO setini yeniden oluşturur - fmt.Println("\u001B[32mSuccess!\u001B[0m") // basarılı mesajı verir + fmt.Println("Success!") } // listAddresses fonksiyonu, cüzdan adreslerini listeler. -func (cli *CommandLine) listAddresses() { - wallets, _ := wallet.CreateWallets() // cüzdan dosyasını okur - addresses := wallets.GetAllAddress() // cüzdan adreslerini alır +func (cli *CommandLine) listAddresses(nodeID string) { + wallets, _ := wallet.CreateWallets(nodeID) // cüzdan dosyasını okur + addresses := wallets.GetAllAddress() // cüzdan adreslerini alır for _, address := range addresses { fmt.Printf("\033[36m %s\u001B[0m\n", address) } } -// CreateWallet fonksiyonu, cüzdan oluşturur. -func (cli *CommandLine) CreateWallet() { - wallets, _ := wallet.CreateWallets() // cüzdan dosyasını okur - address := wallets.AddWallet() // cüzdan adresini oluşturur - wallets.SaveFile() // dosyayı kaydeder +// createWallet fonksiyonu, cüzdan oluşturur. +func (cli *CommandLine) createWallet(nodeID string) { + wallets, _ := wallet.CreateWallets(nodeID) // cüzdan dosyasını okur + address := wallets.AddWallet() // cüzdan adresini oluşturur + wallets.SaveFile(nodeID) // dosyayı kaydeder fmt.Printf("\u001B[32mNew address is : %s\u001B[0m\n", address) } func (cli *CommandLine) Run() { // komut satırı işlemleri cli.validateArgs() // komut satırı argümanlarını dogrular + nodeID := os.Getenv("NODE_ID") // Set-Item -Path Env:NODE_ID -Value "3000" | set NODE_ID=3000 + /* + Set-Item -Path Env:NODE_ID -Value "3000" + Set-Item -Path Env:NODE_ID -Value "4000" + Set-Item -Path Env:NODE_ID -Value "5000" + + xcopy blocks_3000 blocks_5000 + + */ + if nodeID == "" { + fmt.Printf("NODE_ID env ayarlanmadı!") + runtime.Goexit() + } + getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) // getbalance komutunu tanımla createBlockchainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) // createblockchain komutunu tanımla sendCmd := flag.NewFlagSet("send", flag.ExitOnError) // send komutunu tanımla @@ -159,12 +201,16 @@ func (cli *CommandLine) Run() { // komut satırı işlemleri createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) listAddressesCmd := flag.NewFlagSet("listaddresses", flag.ExitOnError) reindexUTXOCmd := flag.NewFlagSet("reindexutxo", flag.ExitOnError) + startNodeCmd := flag.NewFlagSet("startnode", flag.ExitOnError) getBalanceAddress := getBalanceCmd.String("address", "", "\033[36mBakiye almanın adresi\033[0m") createBlockchainAddress := createBlockchainCmd.String("address", "", "\033[36mGenesis blok ödülünün gönderileceği adres\033[0m") sendFrom := sendCmd.String("from", "", "\033[36mKaynak cüzdan adresi\033[0m") sendTo := sendCmd.String("to", "", "\033[36mHedef cüzdan adresi\033[0m") sendAmount := sendCmd.Int("amount", 0, "\033[36mGönderilecek tutar\033[0m") + sendMine := sendCmd.Bool("mine", false, "Aynı düğümde hemen madencilik yapın") + startNodeMiner := startNodeCmd.String("miner", "", "Madencilik modunu etkinleştirin ve ödülü ADDRESS adresine gönderin") + // send komutundaki tutarı tanımla switch os.Args[1] { // komut satırı argümanın hangi komut oldugunu bulur @@ -203,49 +249,61 @@ func (cli *CommandLine) Run() { // komut satırı işlemleri if err != nil { log.Panic(err) } + case "startnode": + err := startNodeCmd.Parse(os.Args[2:]) + if err != nil { + log.Panic(err) + } default: cli.printUsage() // komut satırı argümanlarını yazdır runtime.Goexit() // programın çalışmasını sonlandır } - if getBalanceCmd.Parsed() { // getbalance komutu parse edilirse - if *getBalanceAddress == "" { // getbalance komutundaki adres bilgisi bos ise - getBalanceCmd.Usage() // getbalance komutunu yazdır + if getBalanceCmd.Parsed() { + if *getBalanceAddress == "" { + getBalanceCmd.Usage() runtime.Goexit() } - cli.getBalance(*getBalanceAddress) // getbalance komutunu çalıştır + cli.getBalance(*getBalanceAddress, nodeID) } - if createBlockchainCmd.Parsed() { // createblockchain komutu parse edilirse - if *createBlockchainAddress == "" { // createblockchain komutundaki adres bilgisi bos ise - createBlockchainCmd.Usage() // createblockchain komutunu yazdır + if createBlockchainCmd.Parsed() { + if *createBlockchainAddress == "" { + createBlockchainCmd.Usage() runtime.Goexit() } - cli.createBlockChain(*createBlockchainAddress) // createblockchain komutunu çalıştır + cli.createBlockChain(*createBlockchainAddress, nodeID) } - if printChainCmd.Parsed() { // printchain komutu parse edilirse - cli.printChain() // printchain komutunu çalıştır - } - - if sendCmd.Parsed() { // send komutu parse edilirse - if *sendFrom == "" || *sendTo == "" || *sendAmount <= 0 { // send komutundaki kaynak, hedef ve tutar bilgileri bos ise - sendCmd.Usage() // send komutunu yazdır - runtime.Goexit() - } - - cli.send(*sendFrom, *sendTo, *sendAmount) // send komutunu çalıştır + if printChainCmd.Parsed() { + cli.printChain(nodeID) } if createWalletCmd.Parsed() { - cli.CreateWallet() + cli.createWallet(nodeID) } - if listAddressesCmd.Parsed() { - cli.listAddresses() + cli.listAddresses(nodeID) } - if reindexUTXOCmd.Parsed() { - cli.reindexUTXO() + cli.reindexUTXO(nodeID) + } + + if sendCmd.Parsed() { + if *sendFrom == "" || *sendTo == "" || *sendAmount <= 0 { + sendCmd.Usage() + runtime.Goexit() + } + + cli.send(*sendFrom, *sendTo, *sendAmount, nodeID, *sendMine) + } + + if startNodeCmd.Parsed() { + nodeID := os.Getenv("NODE_ID") + if nodeID == "" { + startNodeCmd.Usage() + runtime.Goexit() + } + cli.StartNode(nodeID, *startNodeMiner) } } diff --git a/main.go b/main.go index 2269dd9..b9d9804 100644 --- a/main.go +++ b/main.go @@ -2,17 +2,12 @@ package main import ( "github.com/SadikSunbul/GO-BlockChain-Simulation/cli" - "github.com/SadikSunbul/GO-BlockChain-Simulation/wallet" "os" ) func main() { - defer os.Exit(0) // programı sonlandırır - cli := cli.CommandLine{} // Komut satırı işlemleri için kullanılan yapıyı temsil eder. - cli.Run() // Komut satırı işlemlerini başlatır + defer os.Exit(0) - w := wallet.MakeWallet() - w.Address() - - //fmt.Print(wallet.ValidateAddress("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa")) + cmd := cli.CommandLine{} + cmd.Run() } diff --git a/network/network.go b/network/network.go index 7886cfe..6aff3c3 100644 --- a/network/network.go +++ b/network/network.go @@ -119,7 +119,7 @@ func SendData(addr string, data []byte) { conn, err := net.Dial(protocol, addr) if err != nil { - fmt.Printf("%s is not available\n", addr) + fmt.Printf("%s mevcut değil\n", addr) var updatedNodes []string for _, node := range KnownNodes { diff --git a/tmp/blocks/000000.vlog b/tmp/blocks/000000.vlog deleted file mode 100644 index 7c69485..0000000 Binary files a/tmp/blocks/000000.vlog and /dev/null differ diff --git a/tmp/blocks/000012.sst b/tmp/blocks/000012.sst deleted file mode 100644 index 4f702ff..0000000 Binary files a/tmp/blocks/000012.sst and /dev/null differ diff --git a/tmp/blocks/MANIFEST b/tmp/blocks/MANIFEST deleted file mode 100644 index 922b5d0..0000000 Binary files a/tmp/blocks/MANIFEST and /dev/null differ diff --git a/tmp/wallets.data b/tmp/wallets.data deleted file mode 100644 index b9e2259..0000000 Binary files a/tmp/wallets.data and /dev/null differ diff --git a/wallet/wallets.go b/wallet/wallets.go index 53fe42a..0c24845 100644 --- a/wallet/wallets.go +++ b/wallet/wallets.go @@ -9,18 +9,18 @@ import ( "os" ) -const walletFile = "./tmp/wallets.data" //Badgerı kullanmıycaz buradakı cuzdsanı saklamak ıcın +const walletFile = "./tmp/wallets_%s.data" //Badgerı kullanmıycaz buradakı cuzdsanı saklamak ıcın type Wallets struct { Wallets map[string]*Wallet } // CreateWallets fonksiyonu, bir Wallets nesnesi olusturur -func CreateWallets() (*Wallets, error) { +func CreateWallets(nodeId string) (*Wallets, error) { wallets := Wallets{} // wallet nesnesi olusturulur wallets.Wallets = make(map[string]*Wallet) // wallet nesnesi olusturulur - err := wallets.LoadFile() // wallets dosyası okunur + err := wallets.LoadFile(nodeId) // wallets dosyası okunur return &wallets, err // wallets nesnesi döndürülür } @@ -48,7 +48,8 @@ func (ws *Wallets) GetAllAddress() []string { } // LoadFile fonksiyonu, dosya okunur -func (ws *Wallets) LoadFile() error { +func (ws *Wallets) LoadFile(nodeId string) error { + walletFile := fmt.Sprintf(walletFile, nodeId) if _, err := os.Stat(walletFile); os.IsNotExist(err) { // dosya yoksa return err // hata döndürür } @@ -73,8 +74,9 @@ func (ws *Wallets) LoadFile() error { } // SaveFile fonksiyonu, dosya kaydedilir -func (ws *Wallets) SaveFile() { +func (ws *Wallets) SaveFile(nodeId string) { var content bytes.Buffer + walletFile := fmt.Sprintf(walletFile, nodeId) gob.Register(elliptic.P256()) // elliptic nesnesi olusturulur encoder := gob.NewEncoder(&content) // encoder nesnesi oluşturulur