Skip to content

Commit

Permalink
Cüzdan yapısı eklendi
Browse files Browse the repository at this point in the history
*Para transferlerı ıcın cuzdan yapısı duzenlendi
* Hatasız çalışıyor durumda
* Terminal düzenlendi
  • Loading branch information
SadikSunbul committed Jun 21, 2024
1 parent 200ea37 commit e807b77
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 97 deletions.
67 changes: 56 additions & 11 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package blockchain

import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"github.com/dgraph-io/badger"
"os"
Expand Down Expand Up @@ -151,7 +154,7 @@ func (iter *BlockChainIterator) Next() *Block {
}

// 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(address string) []Transaction {
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

Expand All @@ -175,7 +178,7 @@ func (chain *BlockChain) FindUnspentTransactions(address string) []Transaction {
}

// Eğer çıktı, belirtilen adrese gönderilmişse
if out.CanBeUnlocked(address) { //aranan adres tarafından acılıp acılmayacagı kontrol edılır
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
}
}
Expand All @@ -185,7 +188,7 @@ func (chain *BlockChain) FindUnspentTransactions(address string) []Transaction {
// İşlemin girdileri üzerinde döngü
for _, in := range tx.Inputs {
// Eğer bu girişin kilidi (unlock) belirtilen adrese açılabiliyorsa
if in.CanUnlock(address) {
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
}
Expand All @@ -203,13 +206,13 @@ func (chain *BlockChain) FindUnspentTransactions(address string) []Transaction {
}

// FindUTXO fonksiyonu, belirtilen bir adrese gönderilmiş ve henüz harcanmamış (UTXO) çıktıları bulmak için kullanılır.
func (chain *BlockChain) FindUTXO(address string) []TxOutput {
var UTXOs []TxOutput // Harcanmamış çıktıları (UTXO'ları) tutacak slice oluşturulur
unspentTransactions := chain.FindUnspentTransactions(address) // Belirtilen adrese gönderilmiş harcanmamış işlemleri bul
func (chain *BlockChain) FindUTXO(pubKeyHash []byte) []TxOutput {
var UTXOs []TxOutput // Harcanmamış çıktıları (UTXO'ları) tutacak slice oluşturulur
unspentTransactions := chain.FindUnspentTransactions(pubKeyHash) // Belirtilen adrese gönderilmiş harcanmamış işlemleri bul

for _, tx := range unspentTransactions { // Her harcanmamış işlem için döngü
for _, out := range tx.Outputs { // İşlemin çıktıları üzerinde döngü
if out.CanBeUnlocked(address) { // Çıktı, belirtilen adrese gönderilmişse
if out.IsLockedWithKey(pubKeyHash) { // Çıktı, belirtilen adrese gönderilmişse
UTXOs = append(UTXOs, out) // UTXO'lar listesine çıktıyı ekle
}
}
Expand All @@ -219,9 +222,9 @@ func (chain *BlockChain) FindUTXO(address string) []TxOutput {

// FindSpendableOutputs, belirtilen bir adrese gönderilmiş ve henüz harcanmamış çıktıları (UTXO'ları) bulmak için kullanılır.
// Ayrıca, bu çıktılar aracılığıyla belirli bir miktar token transfer edilebilecek çıktıları belirler.
func (chain *BlockChain) FindSpendableOutputs(address string, amount int) (int, map[string][]int) {
unspentOuts := make(map[string][]int) // Harcanmamış çıktıları (UTXO'ları) tutacak map
unspentTxs := chain.FindUnspentTransactions(address) // Belirtilen adrese gönderilmiş harcanmamış işlemleri bul
func (chain *BlockChain) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int) {
unspentOuts := make(map[string][]int) // Harcanmamış çıktıları (UTXO'ları) tutacak map
unspentTxs := chain.FindUnspentTransactions(pubKeyHash) // Belirtilen adrese gönderilmiş harcanmamış işlemleri bul

accumulated := 0 // Toplam biriktirilen miktar

Expand All @@ -230,7 +233,7 @@ Work:
txID := hex.EncodeToString(tx.ID) // İşlem ID'sini hex formatına dönüştür

for outIdx, out := range tx.Outputs { // İşlemin çıktıları üzerinde döngü
if out.CanBeUnlocked(address) && accumulated < amount { // Çıktı, belirtilen adrese gönderilmiş ve biriktirilen miktar istenilen miktarı aşmamışsa
if out.IsLockedWithKey(pubKeyHash) && accumulated < amount { // Çıktı, belirtilen adrese gönderilmiş ve biriktirilen miktar istenilen miktarı aşmamışsa
accumulated += out.Value // Çıktının değerini biriktirilen miktar'a ekle
unspentOuts[txID] = append(unspentOuts[txID], outIdx) // Harcanmamış çıktıları map'e ekle

Expand All @@ -243,3 +246,45 @@ Work:

return accumulated, unspentOuts // Biriktirilen toplam miktarı ve harcanmamış çıktıları map olarak döndür
}
func (bc *BlockChain) FindTransaction(ID []byte) (Transaction, error) {
iter := bc.Iterator()

for {
block := iter.Next()

for _, tx := range block.Transactions {
if bytes.Compare(tx.ID, ID) == 0 {
return *tx, nil
}
}

if len(block.PrevHash) == 0 {
break
}
}

return Transaction{}, errors.New("Transaction does not exist")
}
func (bc *BlockChain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey) {
prevTXs := make(map[string]Transaction)

for _, in := range tx.Inputs {
prevTX, err := bc.FindTransaction(in.ID)
Handle(err)
prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
}

tx.Sign(privKey, prevTXs)
}

func (bc *BlockChain) VerifyTransaction(tx *Transaction) bool {
prevTXs := make(map[string]Transaction)

for _, in := range tx.Inputs {
prevTX, err := bc.FindTransaction(in.ID)
Handle(err)
prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
}

return tx.Verify(prevTXs)
}
185 changes: 160 additions & 25 deletions blockchain/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ package blockchain

import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/gob"
"encoding/hex"
"fmt"
"github.com/SadikSunbul/GO-BlockChain-Simulation/wallet"
"log"
"math/big"
"strings"
)

type Transaction struct {
Expand All @@ -20,11 +26,11 @@ func CoinbaseTx(to, data string) *Transaction {
data = fmt.Sprintf("Coins to %s", to) //paralar to da der
}

txin := TxInput{[]byte{}, -1, data} //hıcbır cıktıya referabs vermez ,cıkıs endexi -1 aynı referans yok , sadce data mesajı vardır
txout := TxOutput{100, to} //100 tokeni to ya gonderırı
txin := TxInput{[]byte{}, -1, nil, []byte(data)} //hıcbır cıktıya referabs vermez ,cıkıs endexi -1 aynı referans yok , sadce data mesajı vardır
txout := NewTXOutput(100, to) //100 tokeni to ya gonderırı

tx := Transaction{nil, []TxInput{txin}, []TxOutput{txout}} //transectıonı olustururuz
tx.SetID() //Transectıon Id sını olustururuz
tx := Transaction{nil, []TxInput{txin}, []TxOutput{*txout}} //transectıonı olustururuz
tx.SetID() //Transectıon Id sını olustururuz
return &tx
}

Expand All @@ -42,44 +48,40 @@ func (tx *Transaction) SetID() { //Id olusturur transectıonun

// 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, chain *BlockChain) *Transaction {
var inputs []TxInput // İşlem girişleri (input'ları) için boş slice
var outputs []TxOutput // İşlem çıktıları (output'ları) için boş slice
var inputs []TxInput
var outputs []TxOutput

// Gönderen adresten belirtilen miktar kadar harcanabilir çıktıları bul
acc, validOutputs := chain.FindSpendableOutputs(from, amount)
wallets, err := wallet.CreateWallets()
Handle(err)
w := wallets.GetWallet(from)
pubKeyHash := wallet.PublicKeyHash(w.PublicKey)
acc, validOutputs := chain.FindSpendableOutputs(pubKeyHash, amount)

// Eğer hesaplanan toplam miktar istenilen miktardan az ise hata ver ve işlemi sonlandır
if acc < amount {
log.Panic("Error: yeterli fon yok")
log.Panic("Error: not enough funds")
}

// Geçerli (harcanabilir) çıktılar üzerinde döngü
for txid, outs := range validOutputs {
txID, err := hex.DecodeString(txid) // İşlem ID'sini byte dizisine dönüştür
Handle(err) // Hata varsa işlemi sonlandır
txID, err := hex.DecodeString(txid)
Handle(err)

// Çıktı endeksleri üzerinde döngü
for _, out := range outs {
input := TxInput{txID, out, from} // Yeni bir işlem girişi oluştur
inputs = append(inputs, input) // Oluşturulan girişi input'lar listesine ekle
input := TxInput{txID, out, nil, w.PublicKey}
inputs = append(inputs, input)
}
}

// Yeni bir çıktı oluştur ve belirtilen adrese belirtilen miktarı gönder
outputs = append(outputs, TxOutput{amount, to})
outputs = append(outputs, *NewTXOutput(amount, to))

// Eğer hesaplanan toplam miktar istenilen miktardan fazlaysa, geri kalan miktarı gönderen adrese geri gönder
if acc > amount {
outputs = append(outputs, TxOutput{acc - amount, from})
outputs = append(outputs, *NewTXOutput(acc-amount, from))
}

// Yeni bir işlem (transaction) oluştur
tx := Transaction{nil, inputs, outputs}
tx.ID = tx.Hash()
chain.SignTransaction(&tx, w.PrivateKey)

// İşlem ID'sini hesapla ve işlem nesnesine ata
tx.SetID()

return &tx // Oluşturulan işlem nesnesini işaretçi olarak döndür
return &tx
}

/*
Expand All @@ -93,3 +95,136 @@ func (tx *Transaction) IsCoinbase() bool {
// Bir coinbase işlemi sadece bir girişe sahiptir.
// Bu girişin işlem kimliği (ID) uzunluğu 0'a eşit olmalıdır ve çıkış (Out) -1 olmalıdır.
}

func (tx Transaction) Serilize() []byte {
var encoded bytes.Buffer
enc := gob.NewEncoder(&encoded)

err := enc.Encode(tx)
if err != nil {
log.Panic(err)
}
return encoded.Bytes()
}

func (tx *Transaction) Hash() []byte {
var hash [32]byte
txCopy := *tx
txCopy.ID = []byte{}
hash = sha256.Sum256(txCopy.Serilize())
return hash[:]
}

func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTXs map[string]Transaction) {
if tx.IsCoinbase() {
return
}

for _, in := range tx.Inputs {
if prevTXs[hex.EncodeToString(in.ID)].ID == nil {
log.Panic("ERROR: Previous transaction is not correct")
}
}

txCopy := tx.TrimmedCopy()

for inId, in := range txCopy.Inputs {
prevTX := prevTXs[hex.EncodeToString(in.ID)]
txCopy.Inputs[inId].Signature = nil
txCopy.Inputs[inId].PubKey = prevTX.Outputs[in.Out].PublicKey
txCopy.ID = txCopy.Hash()
txCopy.Inputs[inId].PubKey = nil

r, s, err := ecdsa.Sign(rand.Reader, &privKey, txCopy.ID)
Handle(err)
signature := append(r.Bytes(), s.Bytes()...)

tx.Inputs[inId].Signature = signature

}
}

func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool {
if tx.IsCoinbase() {
return true
}

for _, in := range tx.Inputs {
if prevTXs[hex.EncodeToString(in.ID)].ID == nil {
log.Panic("Previous transaction not correct")
}
}

txCopy := tx.TrimmedCopy()
curve := elliptic.P256()

for inId, in := range tx.Inputs {
prevTx := prevTXs[hex.EncodeToString(in.ID)]
txCopy.Inputs[inId].Signature = nil
txCopy.Inputs[inId].PubKey = prevTx.Outputs[in.Out].PublicKey
txCopy.ID = txCopy.Hash()
txCopy.Inputs[inId].PubKey = nil

r := big.Int{}
s := big.Int{}

sigLen := len(in.Signature)
r.SetBytes(in.Signature[:(sigLen / 2)])
s.SetBytes(in.Signature[(sigLen / 2):])

x := big.Int{}
y := big.Int{}
keyLen := len(in.PubKey)
x.SetBytes(in.PubKey[:(keyLen / 2)])
y.SetBytes(in.PubKey[(keyLen / 2):])

rawPubKey := ecdsa.PublicKey{curve, &x, &y}
if ecdsa.Verify(&rawPubKey, txCopy.ID, &r, &s) == false {
return false
}
}

return true
}

func (tx *Transaction) TrimmedCopy() Transaction {
var inputs []TxInput
var outputs []TxOutput

for _, in := range tx.Inputs {
inputs = append(inputs, TxInput{in.ID, in.Out, nil, nil})
}

for _, out := range tx.Outputs {
outputs = append(outputs, TxOutput{out.Value, out.PublicKey})
}

txCopy := Transaction{tx.ID, inputs, outputs}

return txCopy
}

func (tx Transaction) String() string {
var lines []string
lines = append(lines, fmt.Sprintf("\033[35m ╔═══════════════════════════════════════════════════════════════════════════════════"))
lines = append(lines, fmt.Sprintf("\033[97m║\033[35m ║ --- Transaction %x:\033[0m", tx.ID))

for i, input := range tx.Inputs {
lines = append(lines, fmt.Sprintf("\033[97m║\033[38;5;94m ║ Input %d:\033[0m", i))

lines = append(lines, fmt.Sprintf("\033[97m║\033[33m ║ TXID: %x\033[0m", input.ID))
lines = append(lines, fmt.Sprintf("\033[97m║\033[33m ║ Out: %d\033[0m", input.Out))
lines = append(lines, fmt.Sprintf("\033[97m║\033[33m ║ Signature:%x\033[0m", input.Signature))
lines = append(lines, fmt.Sprintf("\033[97m║\033[33m ║ PubKey: %x\033[0m", input.PubKey))
}

for i, output := range tx.Outputs {
lines = append(lines, fmt.Sprintf("\033[97m║\033[34m ║ Output %d:\033[0m", i))
lines = append(lines, fmt.Sprintf("\033[97m║\033[36m ║ Value: %d\033[0m", output.Value))
lines = append(lines, fmt.Sprintf("\033[97m║\033[36m ║ Script: %x\033[0m", output.PublicKey))
}

lines = append(lines, fmt.Sprintf("\033[97m║\033[35m ╚═══════════════════════════════════════════════════════════════════════════════════\033[0m"))

return strings.Join(lines, "\n")
}
Loading

0 comments on commit e807b77

Please sign in to comment.