package ledgerstate import ( "fmt" "strconv" "testing" "time" "github.com/iotaledger/hive.go/parameter" "github.com/iotaledger/hive.go/objectstorage" ) var ( iota_ = NewColor("IOTA") eth = NewColor("ETH") transferHash1 = NewTransferHash("TRANSFER1") transferHash2 = NewTransferHash("TRANSFER2") transferHash3 = NewTransferHash("TRANSFER3") transferHash4 = NewTransferHash("TRANSFER4") transferHash5 = NewTransferHash("TRANSFER5") transferHash6 = NewTransferHash("TRANSFER6") addressHash1 = NewAddressHash("ADDRESS1") addressHash2 = NewAddressHash("ADDRESS2") addressHash3 = NewAddressHash("ADDRESS3") addressHash4 = NewAddressHash("ADDRESS4") addressHash5 = NewAddressHash("ADDRESS5") addressHash6 = NewAddressHash("ADDRESS6") pendingReality = NewRealityId("PENDING") ) func init() { if err := parameter.FetchConfig(false); err != nil { panic(err) } } func Benchmark(b *testing.B) { ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput( transferHash1, addressHash1, NewColoredBalance(eth, 1024), ) b.ResetTimer() lastTransferHash := transferHash1 for i := 0; i < b.N; i++ { newTransferHash := NewTransferHash(strconv.Itoa(i)) if err := ledgerState.BookTransfer(NewTransfer(newTransferHash).AddInput( NewTransferOutputReference(lastTransferHash, addressHash1), ).AddOutput( addressHash1, NewColoredBalance(eth, 1024), )); err != nil { b.Error(err) } lastTransferHash = newTransferHash } } func Test(t *testing.T) { ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput( transferHash1, addressHash1, NewColoredBalance(eth, 1024), NewColoredBalance(iota_, 1338), ) ledgerState.CreateReality(pendingReality) transfer := NewTransfer(transferHash2).AddInput( NewTransferOutputReference(transferHash1, addressHash1), ).AddOutput( addressHash3, NewColoredBalance(iota_, 338), ).AddOutput( addressHash3, NewColoredBalance(eth, 337), ).AddOutput( addressHash4, NewColoredBalance(iota_, 1000), ).AddOutput( addressHash4, NewColoredBalance(eth, 1000), ) if err := ledgerState.BookTransfer(transfer); err != nil { t.Error(err) } if err := ledgerState.BookTransfer(NewTransfer(transferHash3).AddInput( NewTransferOutputReference(transferHash1, addressHash1), ).AddOutput( addressHash3, NewColoredBalance(iota_, 338), ).AddOutput( addressHash3, NewColoredBalance(eth, 337), ).AddOutput( addressHash4, NewColoredBalance(iota_, 1000), ).AddOutput( addressHash4, NewColoredBalance(eth, 1000), )); err != nil { t.Error(err) } time.Sleep(1000 * time.Millisecond) objectstorage.WaitForWritesToFlush() ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { fmt.Println(object.(*TransferOutput)) }) return true }) } var transferHashCounter = 0 func generateRandomTransferHash() TransferHash { transferHashCounter++ return NewTransferHash("TRANSFER" + strconv.Itoa(transferHashCounter)) } var addressHashCounter = 0 func generateRandomAddressHash() AddressHash { addressHashCounter++ return NewAddressHash("ADDRESS" + strconv.Itoa(addressHashCounter)) } func initializeLedgerStateWithBalances(numberOfBalances int) (ledgerState *LedgerState, result []*TransferOutputReference) { ledgerState = NewLedgerState("testLedger").Prune() for i := 0; i < numberOfBalances; i++ { transferHash := generateRandomTransferHash() addressHash := generateRandomAddressHash() ledgerState.AddTransferOutput(transferHash, addressHash, NewColoredBalance(iota_, 1024)) result = append(result, NewTransferOutputReference(transferHash, addressHash)) } return } func doubleSpend(ledgerState *LedgerState, transferOutputReference *TransferOutputReference) (result []*TransferOutputReference) { for i := 0; i < 2; i++ { result = append(result, spend(ledgerState, transferOutputReference)) } return } func spend(ledgerState *LedgerState, transferOutputReferences ...*TransferOutputReference) (result *TransferOutputReference) { transferHash := generateRandomTransferHash() addressHash := generateRandomAddressHash() totalInputBalance := uint64(0) transfer := NewTransfer(transferHash) for _, transferOutputReference := range transferOutputReferences { ledgerState.GetTransferOutput(transferOutputReference).Consume(func(object objectstorage.StorableObject) { transferOutput := object.(*TransferOutput) for _, coloredBalance := range transferOutput.GetBalances() { totalInputBalance += coloredBalance.GetValue() } }) transfer.AddInput(transferOutputReference) } transfer.AddOutput( addressHash, NewColoredBalance(iota_, totalInputBalance), ) if err := ledgerState.BookTransfer(transfer); err != nil { panic(err) } result = NewTransferOutputReference(transferHash, addressHash) return } func multiSpend(ledgerState *LedgerState, outputCount int, transferOutputReferences ...*TransferOutputReference) (result []*TransferOutputReference) { transferHash := generateRandomTransferHash() transfer := NewTransfer(transferHash) totalInputBalance := uint64(0) for _, transferOutputReference := range transferOutputReferences { ledgerState.GetTransferOutput(transferOutputReference).Consume(func(object objectstorage.StorableObject) { transferOutput := object.(*TransferOutput) for _, coloredBalance := range transferOutput.GetBalances() { totalInputBalance += coloredBalance.GetValue() } }) transfer.AddInput(transferOutputReference) } for i := 0; i < outputCount; i++ { addressHash := generateRandomAddressHash() transfer.AddOutput( addressHash, NewColoredBalance(iota_, totalInputBalance/uint64(outputCount)), ) result = append(result, NewTransferOutputReference(transferHash, addressHash)) } if err := ledgerState.BookTransfer(transfer); err != nil { panic(err) } return } func TestAggregateAggregatedRealities(t *testing.T) { ledgerState, transferOutputs := initializeLedgerStateWithBalances(3) multiSpend(ledgerState, 1, transferOutputs[0]) outputs0 := multiSpend(ledgerState, 2, multiSpend(ledgerState, 1, transferOutputs[0])[0]) multiSpend(ledgerState, 1, transferOutputs[1]) outputs1 := multiSpend(ledgerState, 2, multiSpend(ledgerState, 1, transferOutputs[1])[0]) multiSpend(ledgerState, 1, transferOutputs[2]) outputs2 := multiSpend(ledgerState, 2, multiSpend(ledgerState, 1, transferOutputs[2])[0]) aggregatedOutputs0 := multiSpend(ledgerState, 2, outputs0[0], outputs1[0]) aggregatedOutputs1 := multiSpend(ledgerState, 2, outputs1[1], outputs2[1]) aggregatedOutputs2 := multiSpend(ledgerState, 2, outputs0[1], outputs2[0]) multiSpend(ledgerState, 1, aggregatedOutputs0[0], aggregatedOutputs1[0]) multiSpend(ledgerState, 1, aggregatedOutputs0[1], aggregatedOutputs2[0]) time.Sleep(2000 * time.Millisecond) objectstorage.WaitForWritesToFlush() if err := ledgerState.GenerateRealityVisualization("realities1.png"); err != nil { t.Error(err) } if err := NewVisualizer(ledgerState).RenderTransferOutputs("outputs1.png"); err != nil { t.Error(err) } multiSpend(ledgerState, 2, outputs0[0], outputs1[0]) time.Sleep(2000 * time.Millisecond) objectstorage.WaitForWritesToFlush() if err := ledgerState.GenerateRealityVisualization("realities2.png"); err != nil { t.Error(err) } if err := NewVisualizer(ledgerState).RenderTransferOutputs("outputs2.png"); err != nil { t.Error(err) } } func TestElevateAggregatedReality(t *testing.T) { ledgerState, transferOutputs := initializeLedgerStateWithBalances(3) // create 2 double spends doubleSpentOutputs1 := doubleSpend(ledgerState, transferOutputs[0]) doubleSpentOutputs2 := doubleSpend(ledgerState, transferOutputs[1]) normalSpend := spend(ledgerState, transferOutputs[2]) doubleSpentOutputs3 := doubleSpend(ledgerState, normalSpend) // send funds from one of the double spends further spentInput := spend(ledgerState, doubleSpentOutputs1[1]) // aggregate further sent funds with other reality outputOfAggregatedReality := spend(ledgerState, spentInput, doubleSpentOutputs2[0]) // double spend further spend to elevate aggregated reality spend(ledgerState, doubleSpentOutputs1[1]) // double spend funds of aggregated reality //spend(ledgerState, spentInput, doubleSpentOutputs2[0]) // spend funds of conflict in aggregated reality further //lastOutputOfAggregatedReality := spend(ledgerState, outputOfAggregatedReality) //spend(ledgerState, lastOutputOfAggregatedReality, doubleSpentOutputs3[1]) spend(ledgerState, spend(ledgerState, spend(ledgerState, outputOfAggregatedReality, spend(ledgerState, doubleSpentOutputs3[1])))) time.Sleep(1000 * time.Millisecond) objectstorage.WaitForWritesToFlush() if err := ledgerState.GenerateRealityVisualization("realities.png"); err != nil { t.Error(err) } if err := NewVisualizer(ledgerState).RenderTransferOutputs("outputs.png"); err != nil { t.Error(err) } } func TestElevate(t *testing.T) { ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput( transferHash1, addressHash1, NewColoredBalance(eth, 1024), NewColoredBalance(iota_, 1338), ) // create first legit spend if err := ledgerState.BookTransfer(NewTransfer(transferHash2).AddInput( NewTransferOutputReference(transferHash1, addressHash1), ).AddOutput( addressHash2, NewColoredBalance(iota_, 1338), ).AddOutput( addressHash2, NewColoredBalance(eth, 1024), )); err != nil { t.Error(err) } // send funds further if err := ledgerState.BookTransfer(NewTransfer(transferHash3).AddInput( NewTransferOutputReference(transferHash2, addressHash2), ).AddOutput( addressHash4, NewColoredBalance(iota_, 1338), ).AddOutput( addressHash4, NewColoredBalance(eth, 1024), )); err != nil { t.Error(err) } if err := ledgerState.BookTransfer(NewTransfer(transferHash4).AddInput( NewTransferOutputReference(transferHash2, addressHash2), ).AddOutput( addressHash4, NewColoredBalance(iota_, 1338), ).AddOutput( addressHash4, NewColoredBalance(eth, 1024), )); err != nil { t.Error(err) } // aggregate realities if err := ledgerState.BookTransfer(NewTransfer(transferHash6).AddInput( NewTransferOutputReference(transferHash3, addressHash4), ).AddInput( NewTransferOutputReference(transferHash4, addressHash4), ).AddOutput( addressHash6, NewColoredBalance(iota_, 2676), ).AddOutput( addressHash6, NewColoredBalance(eth, 2674), )); err != nil { t.Error(err) } // create double spend for first transfer if err := ledgerState.BookTransfer(NewTransfer(transferHash5).AddInput( NewTransferOutputReference(transferHash1, addressHash1), ).AddOutput( addressHash5, NewColoredBalance(iota_, 1338), ).AddOutput( addressHash5, NewColoredBalance(eth, 1024), )); err != nil { t.Error(err) } time.Sleep(1000 * time.Millisecond) objectstorage.WaitForWritesToFlush() ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { fmt.Println(object.(*TransferOutput)) }) return true }) }