diff --git a/src/main.go b/src/main.go index 264544c..f4ea1ce 100644 --- a/src/main.go +++ b/src/main.go @@ -1,33 +1,18 @@ package main import ( - "encoding/json" "fmt" - "io/fs" - "os" "github.com/humblenginr/btc-miner/mining" txn "github.com/humblenginr/btc-miner/transaction" "github.com/humblenginr/btc-miner/utils" - "github.com/humblenginr/btc-miner/validation" - "github.com/x1m3/priorityQueue" ) -var ( - MempoolDirPath = "../mempool" - ValidTxnsDirPath = "../valid-txns" - OutputFilePath = "../output.txt" - ValidTxnsDirPerm = 0755 -) -func Validate(tx txn.Transaction) bool { - for inputIdx := range tx.Vin { - if(!validation.Validate(tx, inputIdx)){ - return false - } - } - return true -} +var OutputFilePath = "../output.txt" + + + func LogDetailsAboutTx(tx txn.Transaction){ txid := tx.TxHash() @@ -37,62 +22,6 @@ func LogDetailsAboutTx(tx txn.Transaction){ fmt.Printf("Filename: %x\n", utils.Hash(rev)) } -func UpdateValidTxns() { - os.RemoveAll(ValidTxnsDirPath) - files, err := os.ReadDir(MempoolDirPath) - if err != nil { - panic(err) - } - var transaction txn.Transaction - for _, f := range files { - txnPath := fmt.Sprintf("%s/%s", MempoolDirPath, f.Name()) - byteResult, _ := os.ReadFile(txnPath) - err = json.Unmarshal(byteResult, &transaction) - if err != nil { - panic(err) - } - isValid := Validate(transaction) - err = os.MkdirAll(ValidTxnsDirPath, fs.FileMode(ValidTxnsDirPerm)) - if err != nil { - panic(err) - } - if(isValid && !transaction.Vin[0].IsCoinbase){ - fileName := fmt.Sprintf("%s/%s", ValidTxnsDirPath, f.Name()) - os.WriteFile(fileName, byteResult, fs.FileMode(ValidTxnsDirPerm)) - } - } -} - - - -func GetTxnsQ() *priorityQueue.Queue { - pq := priorityQueue.New() - files, err := os.ReadDir(MempoolDirPath) - if err != nil { - panic(err) - } - for _, f := range files { - var transaction txn.Transaction - txnPath := fmt.Sprintf("%s/%s", MempoolDirPath, f.Name()) - byteResult, _ := os.ReadFile(txnPath) - err = json.Unmarshal(byteResult, &transaction) - if err != nil { - panic(err) - } - isValid := Validate(transaction) - err = os.MkdirAll(ValidTxnsDirPath, fs.FileMode(ValidTxnsDirPerm)) - if err != nil { - panic(err) - } - if(isValid && !transaction.Vin[0].IsCoinbase){ - transaction.UpdatePriority() - pq.Push(mining.Item(transaction)) - } - } - return pq -} - - func main() { pq := GetTxnsQ() candidateBlock := mining.GetCandidateBlock(pq, true) diff --git a/src/mining/mining.go b/src/mining/mining.go index 43ea6e5..9cce98d 100644 --- a/src/mining/mining.go +++ b/src/mining/mining.go @@ -8,7 +8,6 @@ import ( "time" txn "github.com/humblenginr/btc-miner/transaction" - "github.com/x1m3/priorityQueue" "github.com/humblenginr/btc-miner/utils" ) @@ -26,33 +25,12 @@ func findValidPrevBlockHash(nBits uint32) [32]byte { } } -type Item txn.Transaction -func (i Item) HigherPriorityThan(other priorityQueue.Interface) bool { - return i.Priority > other.(Item).Priority -} var MaxBlockWeight = 4000000 - 1000 // 100 is a buffer amount - - -func GetCandidateBlock(txnPq *priorityQueue.Queue, hasWitness bool) Block { +func GetCandidateBlock(txns []*txn.Transaction, hasWitness bool) Block { tarDif := new(big.Int) - txns := make([]*txn.Transaction, 0) - - totalWeight := 0 - - j: - for { - item := txnPq.Pop() - if (item == nil) { break j } - tx := txn.Transaction((item).(Item)) - if((tx.GetWeight() + totalWeight) <= MaxBlockWeight) { - txns = append(txns, &tx) - totalWeight += tx.GetWeight() - } else {break j} - } - fmt.Sscanf(targetDifficultyHexString, "%064x", tarDif) candidateBlock := Block{} diff --git a/src/transaction/tx.go b/src/transaction/tx.go index 91ab1bb..968d0f9 100644 --- a/src/transaction/tx.go +++ b/src/transaction/tx.go @@ -175,31 +175,6 @@ func (t Transaction) getFeeByWeight() float64 { return float64(t.GetFees())/float64(t.GetWeight()) } -func (t Transaction) weightCalc(witness bool) int { - witness = witness && t.HasWitness() - weight := 8 - if(witness) {weight+=2} - weight += VarIntSerializeSize(uint64(len(t.Vin))) - weight += VarIntSerializeSize(uint64(len(t.Vout))) - for _, in := range t.Vin { - weight += 40 - weight += VarIntSerializeSize(uint64(len(in.ScriptSig)/2)) - } - for _, out := range t.Vout { - weight += 8 - weight += VarIntSerializeSize(uint64(len(out.ScriptPubKey)/2)) - } - if(witness){ - for _, in := range t.Vin { - weight += VarIntSerializeSize(uint64(len(in.Witness))) - for _, w := range in.Witness { - weight += VarIntSerializeSize(uint64(len(w)/2)) - } - } - } - return weight -} - func (t Transaction) GetWeight() int { weight := 0 weight += 16 @@ -220,12 +195,6 @@ func (t Transaction) GetWeight() int { } weight += 16 return weight - -/* baseSize := t.weightCalc(false) - totalSize := t.weightCalc(true) - - return ((baseSize * 4) + totalSize) - */ } func (t Transaction) GetFees() int { diff --git a/src/txnpicker/picker.go b/src/txnpicker/picker.go new file mode 100644 index 0000000..11d8655 --- /dev/null +++ b/src/txnpicker/picker.go @@ -0,0 +1,22 @@ +package txnpicker + +import ( + txn "github.com/humblenginr/btc-miner/transaction" +) + +type TransactionsPicker struct { + MempoolDirPath string + MaxTxWeight int + MaxTotalWeight int +} + +func NewTransactionPicker(mempoolDirPath string, maxTxWeight int, maxTotalWeight int) TransactionsPicker { + return TransactionsPicker{MempoolDirPath: mempoolDirPath, MaxTxWeight: maxTxWeight, MaxTotalWeight: maxTotalWeight} +} + + +// PickTransactionsUsingPQ picks valid transactions from the mempool using priority queue. Transaction with higher fee/weight ratio is considered to be high priority. +func (tp *TransactionsPicker) PickTransactionsUsingPQ() []txn.Transaction { + q := getTxnsQ(tp.MempoolDirPath) +} + diff --git a/src/txnpicker/pq.go b/src/txnpicker/pq.go new file mode 100644 index 0000000..1f2a00e --- /dev/null +++ b/src/txnpicker/pq.go @@ -0,0 +1,54 @@ +package txnpicker + +import ( + "encoding/json" + "fmt" + "os" + + txn "github.com/humblenginr/btc-miner/transaction" + "github.com/humblenginr/btc-miner/validation" + "github.com/x1m3/priorityQueue" +) + +var ( + MempoolDirPath = "../mempool" +) + +type Item txn.Transaction + +func (i Item) HigherPriorityThan(other priorityQueue.Interface) bool { + return i.Priority > other.(Item).Priority +} + +func validateHelper(tx txn.Transaction) bool { + for inputIdx := range tx.Vin { + if(!validation.Validate(tx, inputIdx)){ + return false + } + } + return true +} + +// GetTxnsQ returns a priority queue of valid transactions. It uses the mempoolDirPath as the folder to look for transactions. +func getTxnsQ(mempoolDirPath string) *priorityQueue.Queue { + pq := priorityQueue.New() + files, err := os.ReadDir(MempoolDirPath) + if err != nil { + panic(err) + } + for _, f := range files { + var transaction txn.Transaction + txnPath := fmt.Sprintf("%s/%s", MempoolDirPath, f.Name()) + byteResult, _ := os.ReadFile(txnPath) + err = json.Unmarshal(byteResult, &transaction) + if err != nil { + panic(err) + } + isValid := validateHelper(transaction) + if(isValid && !transaction.Vin[0].IsCoinbase){ + transaction.UpdatePriority() + pq.Push(Item(transaction)) + } + } + return pq +}