package main
import ( "fmt" "sync" )
type AccountState interface { GetAccount(name string) AccountValue }
type AccountValue struct { Name string Balance int64 }
type AccountUpdate struct { Name string BalanceChange int }
type Transaction interface { Updates(state AccountState) ([]AccountUpdate, error) }
type Block struct { Transactions []Transaction }
type AccountDB struct { mu sync.RWMutex accounts map[string]int64 }
func (db *AccountDB) GetAccount(name string) AccountValue { db.mu.RLock() defer db.mu.RUnlock() balance, exists := db.accounts[name] if !exists { return AccountValue{Name: name, Balance: 0} } return AccountValue{Name: name, Balance: balance} }
func (db *AccountDB) ApplyUpdate(update AccountUpdate, locks map[string]*sync.Mutex) { locks[update.Name].Lock() defer locks[update.Name].Unlock() db.mu.Lock() defer db.mu.Unlock()
currentBalance, exists := db.accounts[update.Name]
if !exists {
currentBalance = 0
}
newBalance := int(currentBalance) + update.BalanceChange
if newBalance < 0 {
return // Ignore updates that would cause negative balance
}
db.accounts[update.Name] = int64(newBalance)
}
func ExecuteBlock(block Block) ([]AccountValue, error) { accountDB := &AccountDB{accounts: make(map[string]int64)} accountLocks := make(map[string]*sync.Mutex) var accountLocksMu sync.Mutex
// Initialize account balances for demonstration purposes (if needed)
accountDB.accounts["A"] = 100 // Assuming "A" starts with 100 for transaction to be valid
for _, tx := range block.Transactions {
updates, _ := tx.Updates(accountDB)
for _, update := range updates {
accountLocksMu.Lock()
if _, exists := accountLocks[update.Name]; !exists {
accountLocks[update.Name] = &sync.Mutex{}
}
accountLocksMu.Unlock()
}
}
var wg sync.WaitGroup
txChan := make(chan Transaction)
const N = 4 // Number of workers
for i := 0; i < N; i++ {
go func() {
for tx := range txChan {
updates, err := tx.Updates(accountDB)
if err == nil {
for _, update := range updates {
fmt.Printf("Applying update: %v\n", update)
accountDB.ApplyUpdate(update, accountLocks)
}
} else {
fmt.Printf("Error processing transaction: %v\n", err)
}
wg.Done()
}
}()
}
for _, tx := range block.Transactions {
wg.Add(1)
txChan <- tx
}
close(txChan)
wg.Wait()
var finalState []AccountValue
for name, balance := range accountDB.accounts {
finalState = append(finalState, AccountValue{Name: name, Balance: balance})
fmt.Printf("Final Account: %s, Balance: %d\n", name, balance) // Debug final balances
}
return finalState, nil
}
type TransferTransaction struct { from string to string value int }
func (t TransferTransaction) Updates(state AccountState) ([]AccountUpdate, error) { fromAcc := state.GetAccount(t.from) if fromAcc.Balance < int64(t.value) { return nil, fmt.Errorf("insufficient balance") } return []AccountUpdate{ {Name: t.from, BalanceChange: -t.value}, {Name: t.to, BalanceChange: t.value}, }, nil }
func main() { block := Block{ Transactions: []Transaction{ TransferTransaction{from: "A", to: "B", value: 5}, TransferTransaction{from: "B", to: "C", value: 10}, TransferTransaction{from: "B", to: "C", value: 30}, }, } finalState, err := ExecuteBlock(block) if err != nil { fmt.Println("Error:", err) return }
for _, acc := range finalState {
fmt.Printf("Account: %s, Balance: %d\n", acc.Name, acc.Balance)
}
}