lurkcoin-core/lurkcoin/transactions.go

106 lines
3.1 KiB
Go

//
// lurkcoin
// Copyright © 2020 by luk3yx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package lurkcoin
import (
"fmt"
"math/big"
"math/rand"
"sync"
"time"
)
type Transaction struct {
ID string `json:"id"`
Source string `json:"source"`
SourceServer string `json:"source_server"`
Target string `json:"target"`
TargetServer string `json:"target_server"`
Amount Currency `json:"amount"`
SentAmount Currency `json:"sent_amount"`
ReceivedAmount Currency `json:"received_amount"`
Time int64 `json:"time"`
// If true lurkcoin will attempt to revert the transaction if it is
// rejected. The transaction can still be rejected if this is false.
Revertable bool `json:"revertable"`
}
func (self Transaction) String() string {
return fmt.Sprintf("[%s] %s (sent %s, received %s) - Transaction from %q"+
" on %q to %q on %q.", self.ID, self.Amount,
self.SentAmount.RawString(), self.ReceivedAmount.RawString(),
self.Source, self.SourceServer, self.Target, self.TargetServer)
}
// Get a time.Time object from the transaction's Time attribute.
func (self Transaction) GetTime() time.Time {
return time.Unix(self.Time, 0)
}
// Get the legacy ID
var max_legacy_id *big.Int = big.NewInt(9999999)
func (self *Transaction) GetLegacyID() int32 {
raw := new(big.Int)
raw.Mod(new(big.Int).SetBytes([]byte(self.ID)), max_legacy_id)
// Because 10,000,000 (max_legacy_id + 1) can fit into int64/int32,
// overflows are not an issue here.
return int32(raw.Int64()) + 1
}
// Generate transaction IDs
var mutex = new(sync.Mutex)
var lastTime int64 = -1
var previouslyGenerated map[uint32]bool
func GenerateTransactionID() (string, int64) {
mutex.Lock()
defer mutex.Unlock()
// Ensure too many transaction IDs haven't been generated.
if len(previouslyGenerated) > 1048576 {
// Uh-oh (more than 1 million transactions in a single second)
time.Sleep(1 * time.Second)
}
t := time.Now().Unix()
if t > lastTime {
previouslyGenerated = make(map[uint32]bool)
}
var id uint32
var exists bool = true
for exists {
id = rand.Uint32()
_, exists = previouslyGenerated[id]
}
previouslyGenerated[id] = true
return fmt.Sprintf("T%X-%08X", t, id), t
}
func MakeTransaction(source, sourceServer, target, targetServer string,
amount, sentAmount, receivedAmount Currency) Transaction {
id, time := GenerateTransactionID()
return Transaction{id, source, sourceServer, target, targetServer, amount,
sentAmount, receivedAmount, time, false}
}