Skip to content

Commit

Permalink
fix(node): there is no minimal transaction fee (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyPansier authored Jan 27, 2023
1 parent 248ce9f commit f7d0ce3
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 86 deletions.
5 changes: 3 additions & 2 deletions src/node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
validationIntervalInSeconds = 60
verificationsCountPerValidation = 6
defaultPort = 8106
minimalTransactionFee = 1000
)

func main() {
Expand Down Expand Up @@ -57,8 +58,8 @@ func main() {
now := watch.Now()
initialTimestamp := now.Truncate(validationTimer).Add(validationTimer).UnixNano()
genesisTransaction := validation.NewRewardTransaction(wallet.Address(), initialTimestamp, settings.GenesisAmount)
blockchain := verification.NewBlockchain(genesisTransaction, registry, validationTimer, synchronizer, logger)
pool := validation.NewTransactionsPool(blockchain, registry, wallet.Address(), validationTimer, watch, logger)
blockchain := verification.NewBlockchain(genesisTransaction, minimalTransactionFee, registry, validationTimer, synchronizer, logger)
pool := validation.NewTransactionsPool(blockchain, minimalTransactionFee, registry, wallet.Address(), validationTimer, watch, logger)
validationEngine := tick.NewEngine(pool.Validate, watch, validationTimer, 1, 0)
verificationEngine := tick.NewEngine(blockchain.Update, watch, validationTimer, verificationsCountPerValidation, 1)
serverFactory := gp2p.NewServerFactory()
Expand Down
7 changes: 2 additions & 5 deletions src/node/protocol/validation/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import (
"github.com/my-cloud/ruthenium/src/node/network"
)

const (
transactionFee = 1000
rewardSenderAddress = "REWARD SENDER ADDRESS"
)
const rewardSenderAddress = "REWARD SENDER ADDRESS"

type Transaction struct {
recipientAddress string
Expand All @@ -29,7 +26,7 @@ func NewRewardTransaction(recipientAddress string, timestamp int64, value uint64
SenderAddress: rewardSenderAddress,
Timestamp: timestamp,
Value: value,
Fee: transactionFee,
Fee: 0,
}
}

Expand Down
39 changes: 19 additions & 20 deletions src/node/protocol/validation/transactions_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ type TransactionsPool struct {
transactionResponses []*network.TransactionResponse
mutex sync.RWMutex

blockchain protocol.Blockchain
registry protocol.Registry
validatorAddress string
blockchain protocol.Blockchain
minimalTransactionFee uint64
registry protocol.Registry
validatorAddress string

validationTimer time.Duration
watch clock.Watch

logger log.Logger
}

func NewTransactionsPool(blockchain protocol.Blockchain, registry protocol.Registry, validatorAddress string, validationTimer time.Duration, watch clock.Watch, logger log.Logger) *TransactionsPool {
func NewTransactionsPool(blockchain protocol.Blockchain, minimalTransactionFee uint64, registry protocol.Registry, validatorAddress string, validationTimer time.Duration, watch clock.Watch, logger log.Logger) *TransactionsPool {
pool := new(TransactionsPool)
pool.blockchain = blockchain
pool.minimalTransactionFee = minimalTransactionFee
pool.registry = registry
pool.validatorAddress = validatorAddress
pool.validationTimer = validationTimer
Expand Down Expand Up @@ -153,57 +155,54 @@ func (pool *TransactionsPool) Validate(timestamp int64) {
pool.logger.Debug(fmt.Sprintf("reward: %d", reward))
}

func (pool *TransactionsPool) addTransaction(transactionRequest *network.TransactionRequest) (err error) {
func (pool *TransactionsPool) addTransaction(transactionRequest *network.TransactionRequest) error {
fee := *transactionRequest.Fee
if fee < pool.minimalTransactionFee {
return fmt.Errorf("the transaction fee is too low, fee: %d, minimal fee: %d", fee, pool.minimalTransactionFee)
}
transaction, err := NewTransactionFromRequest(transactionRequest)
if err != nil {
err = fmt.Errorf("failed to instantiate transaction: %w", err)
return
return fmt.Errorf("failed to instantiate transaction: %w", err)
}
currentBlockchain := pool.blockchain.Copy()
blocks := currentBlockchain.Blocks()
if len(blocks) > 1 {
timestamp := transaction.Timestamp()
nextBlockTimestamp := blocks[len(blocks)-1].Timestamp + 2*pool.validationTimer.Nanoseconds()
if nextBlockTimestamp < timestamp {
err = fmt.Errorf("the transaction timestamp is too far in the future: %v, now: %v", time.Unix(0, timestamp), time.Unix(0, nextBlockTimestamp))
return
return fmt.Errorf("the transaction timestamp is too far in the future: %v, now: %v", time.Unix(0, timestamp), time.Unix(0, nextBlockTimestamp))
}
currentBlockTimestamp := blocks[len(blocks)-1].Timestamp
if timestamp < currentBlockTimestamp {
err = fmt.Errorf("the transaction timestamp is too old: %v, current block timestamp: %v", time.Unix(0, timestamp), time.Unix(0, currentBlockTimestamp))
return
return fmt.Errorf("the transaction timestamp is too old: %v, current block timestamp: %v", time.Unix(0, timestamp), time.Unix(0, currentBlockTimestamp))
}
for _, validatedTransaction := range blocks[len(blocks)-1].Transactions {
if transaction.Equals(validatedTransaction) {
err = errors.New("the transaction is already in the blockchain")
return
return errors.New("the transaction is already in the blockchain")
}
}
}
for _, pendingTransaction := range pool.transactionResponses {
if transaction.Equals(pendingTransaction) {
err = errors.New("the transaction is already in the transactions pool")
return
return errors.New("the transaction is already in the transactions pool")
}
}
if err = transaction.VerifySignature(); err != nil {
err = errors.New("failed to verify transaction")
return
return errors.New("failed to verify transaction")
}
var senderWalletAmount uint64
if len(blocks) > 0 {
senderWalletAmount = currentBlockchain.CalculateTotalAmount(blocks[len(blocks)-1].Timestamp, transaction.SenderAddress())
}
insufficientBalance := senderWalletAmount < transaction.Value()+transaction.Fee()
if insufficientBalance {
err = errors.New("not enough balance in the sender wallet")
return
return errors.New("not enough balance in the sender wallet")
}
pool.mutex.Lock()
defer pool.mutex.Unlock()
pool.transactions = append(pool.transactions, transaction)
pool.transactionResponses = append(pool.transactionResponses, transaction.GetResponse())
return
return nil
}

func (pool *TransactionsPool) clear() {
Expand Down
28 changes: 17 additions & 11 deletions src/node/protocol/verification/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,27 @@ const (
)

type Blockchain struct {
blocks []*Block
blockResponses []*network.BlockResponse
lambda float64
mutex sync.RWMutex
registry protocol.Registry
synchronizer network.Synchronizer
validationTimer time.Duration
logger log.Logger
blocks []*Block
blockResponses []*network.BlockResponse
lambda float64
minimalTransactionFee uint64
mutex sync.RWMutex
registry protocol.Registry
synchronizer network.Synchronizer
validationTimer time.Duration
logger log.Logger
}

func NewBlockchain(genesisTransaction *network.TransactionResponse, registry protocol.Registry, validationTimer time.Duration, synchronizer network.Synchronizer, logger log.Logger) *Blockchain {
blockchain := newBlockchain(nil, registry, validationTimer, synchronizer, logger)
func NewBlockchain(genesisTransaction *network.TransactionResponse, minimalTransactionFee uint64, registry protocol.Registry, validationTimer time.Duration, synchronizer network.Synchronizer, logger log.Logger) *Blockchain {
blockchain := newBlockchain(nil, minimalTransactionFee, registry, validationTimer, synchronizer, logger)
blockchain.addGenesisBlock(genesisTransaction)
return blockchain
}

func newBlockchain(blockResponses []*network.BlockResponse, registry protocol.Registry, validationTimer time.Duration, synchronizer network.Synchronizer, logger log.Logger) *Blockchain {
func newBlockchain(blockResponses []*network.BlockResponse, minimalTransactionFee uint64, registry protocol.Registry, validationTimer time.Duration, synchronizer network.Synchronizer, logger log.Logger) *Blockchain {
blockchain := new(Blockchain)
blockchain.blockResponses = blockResponses
blockchain.minimalTransactionFee = minimalTransactionFee
blockchain.registry = registry
blockchain.validationTimer = validationTimer
blockchain.synchronizer = synchronizer
Expand Down Expand Up @@ -399,6 +401,7 @@ func (blockchain *Blockchain) verify(neighborBlocks []*network.BlockResponse, ho
validBlocks = append(validBlocks, previousBlock)
neighborBlockchain := newBlockchain(
append(oldHostBlocks, neighborBlocks...),
blockchain.minimalTransactionFee,
blockchain.registry,
blockchain.validationTimer,
blockchain.synchronizer,
Expand Down Expand Up @@ -469,6 +472,9 @@ func (blockchain *Blockchain) verify(neighborBlocks []*network.BlockResponse, ho
return nil, fmt.Errorf("neighbor transaction is invalid: %w", err)
}
fee := transaction.Fee()
if fee < blockchain.minimalTransactionFee {
return nil, fmt.Errorf("a neighbor block transaction fee is too low, fee: %d, minimal fee: %d", fee, blockchain.minimalTransactionFee)
}
totalTransactionsValueBySenderAddress[transaction.SenderAddress()] += transaction.Value() + fee
totalTransactionsFees += fee
if currentBlockTimestamp+blockchain.validationTimer.Nanoseconds() < transaction.Timestamp() {
Expand Down
3 changes: 2 additions & 1 deletion src/ui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
const (
defaultPort = 8080
defaultHostPort = 8106
transactionFee = 1000
)

func main() {
Expand Down Expand Up @@ -52,7 +53,7 @@ func main() {
particlesCount := settings.ParticlesCount
http.Handle("/", index.NewHandler(*templatesPath, logger))
http.Handle("/wallet", wallet.NewHandler(*mnemonic, *derivationPath, *password, *privateKey, logger))
http.Handle("/transaction", transaction.NewHandler(host, particlesCount, logger))
http.Handle("/transaction", transaction.NewHandler(host, particlesCount, transactionFee, logger))
http.Handle("/transactions", transactions.NewHandler(host, logger))
http.Handle("/wallet/amount", amount.NewHandler(host, particlesCount, logger))
http.Handle("/validation/start", start.NewHandler(host, logger))
Expand Down
6 changes: 2 additions & 4 deletions src/ui/server/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"github.com/my-cloud/ruthenium/src/node/network"
)

const transactionFee = 1000

type Transaction struct {
recipientAddress string
senderAddress string
Expand All @@ -19,14 +17,14 @@ type Transaction struct {
fee uint64
}

func NewTransaction(recipientAddress string, senderAddress string, senderPublicKey *encryption.PublicKey, timestamp int64, value uint64) *Transaction {
func NewTransaction(recipientAddress string, senderAddress string, senderPublicKey *encryption.PublicKey, timestamp int64, value uint64, fee uint64) *Transaction {
return &Transaction{
recipientAddress: recipientAddress,
senderAddress: senderAddress,
senderPublicKey: senderPublicKey,
timestamp: timestamp,
value: value,
fee: transactionFee,
fee: fee,
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/ui/server/transaction/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import (
type Handler struct {
host network.Neighbor
particlesInOneAtom uint64
transactionFee uint64
logger log.Logger
}

func NewHandler(host network.Neighbor, particlesInOneAtom uint64, logger log.Logger) *Handler {
return &Handler{host, particlesInOneAtom, logger}
func NewHandler(host network.Neighbor, particlesInOneAtom uint64, transactionFee uint64, logger log.Logger) *Handler {
return &Handler{host, particlesInOneAtom, transactionFee, logger}
}

func (handler *Handler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
Expand Down Expand Up @@ -59,7 +60,7 @@ func (handler *Handler) ServeHTTP(writer http.ResponseWriter, req *http.Request)
return
}
senderPublicKey := encryption.NewPublicKey(privateKey)
transaction := server.NewTransaction(*transactionRequest.RecipientAddress, *transactionRequest.SenderAddress, senderPublicKey, time.Now().UnixNano(), value)
transaction := server.NewTransaction(*transactionRequest.RecipientAddress, *transactionRequest.SenderAddress, senderPublicKey, time.Now().UnixNano(), value, handler.transactionFee)
err = transaction.Sign(privateKey)
if err != nil {
handler.logger.Error(fmt.Errorf("failed to generate signature: %w", err).Error())
Expand Down
1 change: 0 additions & 1 deletion test/dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ const (
Mnemonic2 = "screen wrap color drop lady keep dwarf horror recipe gap ride garage"
DerivationPath = "m/44'/60'/0'/0/0"
PrivateKey = "0x48913790c2bebc48417491f96a7e07ec94c76ccd0fe1562dc1749479d9715afd"
PublicKey = "0x046bd857ce80ff5238d6561f3a775802453c570b6ea2cbf93a35a8a6542b2edbe5f625f9e3fbd2a5df62adebc27391332a265fb94340fb11b69cf569605a5df782"
Address = "0x9C69443c3Ec0D660e257934ffc1754EB9aD039CB"
)
Loading

0 comments on commit f7d0ce3

Please sign in to comment.