diff --git a/.gitignore b/.gitignore
index 0566492..d4bc9b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,4 +23,4 @@ go.work
node_modules/
.DS_Store
-chain_storage/
+chain_storage*/
diff --git a/README.md b/README.md
index 9713743..83cd111 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ go run cmd/blockchain/main.go -address localhost:8080 -http localhost:8090 -stor
go run cmd/blockchain/main.go -address localhost:8081 -peers localhost:8080 -http localhost:8091 -storage chain_storage_2
-go run cmd/blockchain/main.goo -address localhost:8082 -peers localhost:8080,localhost:8081 -http localhost:8092 -storage chain_storage_3
+go run cmd/blockchain/main.go -address localhost:8082 -peers localhost:8080,localhost:8081 -http localhost:8092 -storage chain_storage_3
```
### Generate private key for testing
diff --git a/api/api.go b/api/api.go
index 756da1b..583fc14 100644
--- a/api/api.go
+++ b/api/api.go
@@ -78,7 +78,7 @@ func (h *Handler) MineBlock(w http.ResponseWriter, r *http.Request) {
h.StatusesRWLock.Lock()
h.MiningStatuses[id] = MineStatusResponse{Status: StatusPending}
h.StatusesRWLock.Unlock()
- err := h.Blockchain.MinePendingTransactions("")
+ block, err := h.Blockchain.MinePendingTransactions("")
if err != nil {
h.StatusesRWLock.Lock()
h.MiningStatuses[id] = MineStatusResponse{
@@ -86,9 +86,11 @@ func (h *Handler) MineBlock(w http.ResponseWriter, r *http.Request) {
Details: fmt.Sprintf("Error: %v", err),
}
h.StatusesRWLock.Unlock()
+ return
}
h.StatusesRWLock.Lock()
h.MiningStatuses[id] = MineStatusResponse{Status: StatusSuccessful}
+ go h.Node.BroadcastBlock(block)
h.StatusesRWLock.Unlock()
}()
err := json.NewEncoder(w).Encode(MineResponse{Id: id.String()})
diff --git a/chain/chain.go b/chain/chain.go
index fc7567f..fcfbd59 100644
--- a/chain/chain.go
+++ b/chain/chain.go
@@ -273,16 +273,28 @@ func (chain *Blockchain) IsValid() bool {
return true
}
-func (chain *Blockchain) MinePendingTransactions(minerAddress string) error {
+func (chain *Blockchain) MinePendingTransactions(minerAddress string) (Block, error) {
currentPoolSize := len(chain.PendingTransactions)
+ if currentPoolSize == 0 {
+ return Block{}, errors.New("Transaction pool is empty")
+ }
+
var transactions []Transaction
if currentPoolSize < chain.MaxBlockSize {
transactions = chain.PendingTransactions[0:currentPoolSize]
chain.PendingTransactions = chain.PendingTransactions[currentPoolSize:]
+ err := chain.Storage.DequeueTransactions(currentPoolSize)
+ if err != nil {
+ fmt.Println("Could not dequeue transactions from storage")
+ }
} else {
transactions = chain.PendingTransactions[0 : chain.MaxBlockSize-1]
chain.PendingTransactions = chain.PendingTransactions[chain.MaxBlockSize-1:]
+ err := chain.Storage.DequeueTransactions(chain.MaxBlockSize - 1)
+ if err != nil {
+ fmt.Println("Could not dequeue transactions from storage")
+ }
}
rewardTx := Transaction{
@@ -302,13 +314,15 @@ func (chain *Blockchain) MinePendingTransactions(minerAddress string) error {
}
block.Hash = block.CalculateHash()
+ // TODO: sync transaction removal between nodes
+ // TODO: recover if mining failed
block.MineBlock(chain.Difficulty)
chain.AddBlock(block)
err := chain.Storage.AddBlock(block)
if err != nil {
- return err
+ return Block{}, err
}
- return nil
+ return block, nil
}
type Storage interface {
@@ -316,6 +330,7 @@ type Storage interface {
AddBlock(b Block) error
AddTransaction(t Transaction) error
Reset(chain *Blockchain) error
+ DequeueTransactions(n int) error
}
func InitBlockchain(difficulty, maxBlockSize int, miningReward float64, s Storage) *Blockchain {
diff --git a/cmd/private_key_generator/main.go b/cmd/private_key_generator/main.go
index 8330a67..2f29305 100644
--- a/cmd/private_key_generator/main.go
+++ b/cmd/private_key_generator/main.go
@@ -9,6 +9,7 @@ func main() {
wallet := chain.Wallet{}
wallet.KeyGen()
fmt.Println(wallet.PrivateKey)
+ fmt.Println(wallet.PublicKey)
t := chain.Transaction{}
err := t.Sign(wallet.PrivateKey)
if err != nil {
diff --git a/frontend/src/AddTransactionModalButton.tsx b/frontend/src/AddTransactionModalButton.tsx
index ce87017..9adff1e 100644
--- a/frontend/src/AddTransactionModalButton.tsx
+++ b/frontend/src/AddTransactionModalButton.tsx
@@ -12,14 +12,23 @@ import {
import AddTransactionForm from './AddTransactionForm'
-export default function AddTransactionsModalButton() {
- const { isOpen, onOpen, onClose } = useDisclosure()
+interface AddTransactionsModalButtonProps {
+ onClose: () => void;
+ }
+
+export default function AddTransactionsModalButton({ onClose }: AddTransactionsModalButtonProps) {
+ const { isOpen, onOpen, onClose: closeModal } = useDisclosure()
+
+ const handleClose = () => {
+ closeModal();
+ onClose();
+ };
return (
<>
-
+
@@ -39,7 +48,7 @@ export default function AddTransactionsModalButton() {
-
diff --git a/frontend/src/TransactionsPage.tsx b/frontend/src/TransactionsPage.tsx
index e0629ad..bdd538d 100644
--- a/frontend/src/TransactionsPage.tsx
+++ b/frontend/src/TransactionsPage.tsx
@@ -12,17 +12,21 @@ async function fetchTransactions(): Promise {
}
export default function TransactionsPage({ caption }: { caption: string }) {
- const { isPending, error, data } = useQuery({
+ const { isPending, error, data, refetch } = useQuery({
queryKey: ["transactions"],
queryFn: fetchTransactions,
});
+ const handleRefetch = () => {
+ refetch();
+ };
+
if (!data || !data.length) {
return (
<>
<>No transactions yet.>
-
+
>
);
@@ -34,7 +38,7 @@ export default function TransactionsPage({ caption }: { caption: string }) {
<>
-
+
>
);
diff --git a/storage/badger.go b/storage/badger.go
index 946f0de..61b64f8 100644
--- a/storage/badger.go
+++ b/storage/badger.go
@@ -158,6 +158,33 @@ func (bs *Storage) AddTransaction(t chain.Transaction) error {
return err
}
+func (bs *Storage) DequeueTransactions(n int) error {
+ return bs.db.Update(func(txn *badger.Txn) error {
+ opts := badger.DefaultIteratorOptions
+ opts.PrefetchValues = false
+ it := txn.NewIterator(opts)
+ defer it.Close()
+
+ prefix := []byte(transactionPrefix)
+ count := 0
+
+ for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
+ if count >= n {
+ break
+ }
+
+ key := it.Item().Key()
+ if err := txn.Delete(key); err != nil {
+ return err
+ }
+
+ count++
+ }
+
+ return nil
+ })
+}
+
func (storage *Storage) deleteByPrefix(prefix []byte) error {
deleteKeys := func(keysForDelete [][]byte) error {
if err := storage.db.Update(func(txn *badger.Txn) error {