Skip to content

Commit

Permalink
Feat: added test framework
Browse files Browse the repository at this point in the history
  • Loading branch information
hmoog committed Mar 31, 2022
1 parent d24f466 commit 2819366
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 47 deletions.
14 changes: 14 additions & 0 deletions packages/refactored/ledger/booker.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ func NewBooker(ledger *Ledger) (new *Booker) {
}
}

func (b *Booker) checkAlreadyBookedCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
if params.TransactionMetadata == nil {
cachedTransactionMetadata := b.CachedTransactionMetadata(params.Transaction.ID())
defer cachedTransactionMetadata.Release()
params.TransactionMetadata, _ = cachedTransactionMetadata.Unwrap()
}

if params.TransactionMetadata.Booked() {
return nil
}

return next(params)
}

func (b *Booker) bookTransactionCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
b.bookTransaction(params.TransactionMetadata, params.InputsMetadata, params.Consumers, params.Outputs)

Expand Down
11 changes: 10 additions & 1 deletion packages/refactored/ledger/dataflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ledger

import (
"github.com/iotaledger/hive.go/generics/dataflow"
"github.com/iotaledger/hive.go/generics/event"
)

type DataFlow struct {
Expand All @@ -14,6 +15,14 @@ func NewDataFlow(ledger *Ledger) *DataFlow {
}
}

func (d *DataFlow) Setup() {
d.TransactionBookedEvent.Attach(event.NewClosure[TransactionID](func(txID TransactionID) {
d.CachedTransaction(txID).Consume(func(tx *Transaction) {
_ = d.Ledger.processTransaction(tx)
})
}))
}

func (d *DataFlow) storeAndProcessTransaction() *dataflow.DataFlow[*dataFlowParams] {
return dataflow.New[*dataFlowParams](
d.storeTransactionCommand,
Expand All @@ -23,7 +32,7 @@ func (d *DataFlow) storeAndProcessTransaction() *dataflow.DataFlow[*dataFlowPara

func (d *DataFlow) processTransaction() *dataflow.DataFlow[*dataFlowParams] {
return dataflow.New[*dataFlowParams](
d.initConsumersCommand,
d.checkAlreadyBookedCommand,
d.checkTransaction().ChainedCommand,
d.bookTransactionCommand,
).WithErrorCallback(func(err error, params *dataFlowParams) {
Expand Down
33 changes: 7 additions & 26 deletions packages/refactored/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ type Ledger struct {
TransactionBookedEvent *event.Event[TransactionID]
ErrorEvent *event.Event[error]

DataFlow *DataFlow
*Options
*Storage
*Solidifier
*Validator
*VM
*Booker

*DataFlow
*Options
*Utils

*branchdag.BranchDAG
Expand Down Expand Up @@ -54,7 +55,6 @@ func New(store kvstore.KVStore, vm utxo.VM, options ...Option) (ledger *Ledger)
return ledger
}

// Configure modifies the configuration of the Ledger.
func (l *Ledger) Configure(options ...Option) {
if l.Options == nil {
l.Options = &Options{
Expand All @@ -69,41 +69,22 @@ func (l *Ledger) Configure(options ...Option) {
}
}

func (l *Ledger) Setup() {
l.TransactionBookedEvent.Attach(event.NewClosure[TransactionID](func(txID TransactionID) {
l.CachedTransactionMetadata(txID).Consume(func(txMetadata *TransactionMetadata) {
l.CachedTransaction(txID).Consume(func(tx *Transaction) {
_ = l.processTransaction(tx, txMetadata)
})
})
}))
}

// StoreAndProcessTransaction is the only public facing api
func (l *Ledger) StoreAndProcessTransaction(tx utxo.Transaction) (err error) {
l.Lock(tx.ID())
defer l.Unlock(tx.ID())

return l.DataFlow.storeAndProcessTransaction().Run(&dataFlowParams{
Transaction: NewTransaction(tx),
})
return l.DataFlow.storeAndProcessTransaction().Run(&dataFlowParams{Transaction: NewTransaction(tx)})
}

func (l *Ledger) CheckTransaction(tx utxo.Transaction) (err error) {
return l.DataFlow.checkTransaction().Run(&dataFlowParams{
Transaction: NewTransaction(tx),
InputIDs: l.resolveInputs(tx.Inputs()),
})
return l.DataFlow.checkTransaction().Run(&dataFlowParams{Transaction: NewTransaction(tx)})
}

func (l *Ledger) processTransaction(tx *Transaction, txMetadata *TransactionMetadata) (err error) {
func (l *Ledger) processTransaction(tx *Transaction) (err error) {
l.Lock(tx.ID())
defer l.Unlock(tx.ID())

return l.DataFlow.processTransaction().Run(&dataFlowParams{
Transaction: tx,
TransactionMetadata: txMetadata,
})
return l.DataFlow.processTransaction().Run(&dataFlowParams{Transaction: tx})
}

// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
10 changes: 10 additions & 0 deletions packages/refactored/ledger/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import (
)

func TestLedger(t *testing.T) {
testFramework := NewTestFramework()

testFramework.CreateTransaction("TX1", 2, "Genesis")
testFramework.CreateTransaction("TX2", 2, "TX1.0")
testFramework.CreateTransaction("TX3", 2, "TX1.1")

fmt.Println(testFramework.IssueTransaction("TX2"))

vm := NewMockedVM()

genesisOutput := NewOutput(NewMockedOutput(utxo.EmptyTransactionID, 0))
Expand Down Expand Up @@ -40,6 +48,8 @@ func TestLedger(t *testing.T) {
NewMockedInput(nonExistingOutput.ID()),
}, 2)

fmt.Println("CHECK: ", ledger.CheckTransaction(tx1))

tx1.ID().RegisterAlias("TX1")

fmt.Println(tx1.ID())
Expand Down
16 changes: 3 additions & 13 deletions packages/refactored/ledger/solidifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,11 @@ func NewSolidifier(ledger *Ledger) (new *Solidifier) {
}
}

func (s *Solidifier) initConsumersCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
if params.TransactionMetadata.Booked() {
return nil
func (s *Solidifier) checkSolidityCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
if params.InputIDs.IsEmpty() {
params.InputIDs = s.resolveInputs(params.Transaction.Inputs())
}

params.InputIDs = s.resolveInputs(params.Transaction.Inputs())

cachedConsumers := s.initConsumers(params.InputIDs, params.Transaction.ID())
defer cachedConsumers.Release()
params.Consumers = cachedConsumers.Unwrap()

return next(params)
}

func (s *Solidifier) checkSolidityCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
cachedInputs := s.CachedOutputs(params.InputIDs)
defer cachedInputs.Release()
if params.Inputs = NewOutputs(cachedInputs.Unwrap(true)...); params.Inputs.Size() != len(cachedInputs) {
Expand Down
12 changes: 8 additions & 4 deletions packages/refactored/ledger/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ func NewStorage(ledger *Ledger) (newStorage *Storage) {
}
}

func (d *DataFlow) storeTransactionCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
func (s *Storage) storeTransactionCommand(params *dataFlowParams, next dataflow.Next[*dataFlowParams]) (err error) {
created := false
cachedTransactionMetadata := d.CachedTransactionMetadata(params.Transaction.ID(), func(txID TransactionID) *TransactionMetadata {
d.transactionStorage.Store(params.Transaction).Release()
cachedTransactionMetadata := s.CachedTransactionMetadata(params.Transaction.ID(), func(txID TransactionID) *TransactionMetadata {
s.transactionStorage.Store(params.Transaction).Release()
created = true
return NewTransactionMetadata(txID)
})
Expand All @@ -79,7 +79,11 @@ func (d *DataFlow) storeTransactionCommand(params *dataFlowParams, next dataflow
return errors.Errorf("%s is an unsolid reattachment: %w", params.Transaction.ID(), ErrTransactionUnsolid)
}

d.TransactionStoredEvent.Trigger(params.Transaction.ID())
cachedConsumers := s.initConsumers(params.InputIDs, params.Transaction.ID())
defer cachedConsumers.Release()
params.Consumers = cachedConsumers.Unwrap(true)

s.TransactionStoredEvent.Trigger(params.Transaction.ID())

return next(params)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,80 @@
package ledger

import (
"fmt"
"strconv"
"sync"
"sync/atomic"

"github.com/iotaledger/hive.go/generics/objectstorage"
"github.com/iotaledger/hive.go/kvstore/mapdb"
"github.com/iotaledger/hive.go/marshalutil"
"github.com/iotaledger/hive.go/stringify"

"github.com/iotaledger/goshimmer/packages/refactored/generics"
"github.com/iotaledger/goshimmer/packages/refactored/utxo"
)

// region TestFramework ////////////////////////////////////////////////////////////////////////////////////////////////

type TestFramework struct {
Ledger *Ledger

transactionsByAlias map[string]*MockedTransaction
outputIDsByAlias map[string]OutputID
}

func NewTestFramework(options ...Option) (new *TestFramework) {
new = &TestFramework{
Ledger: New(mapdb.NewMapDB(), NewMockedVM(), options...),

transactionsByAlias: make(map[string]*MockedTransaction),
outputIDsByAlias: make(map[string]OutputID),
}

var genesisOutputID OutputID
genesisOutputID.RegisterAlias("Genesis")

new.outputIDsByAlias["Genesis"] = genesisOutputID

return new
}

func (t *TestFramework) CreateTransaction(txAlias string, outputCount uint16, inputAliases ...string) {
mockedInputs := make([]*MockedInput, 0)
for _, inputAlias := range inputAliases {
outputID, exists := t.outputIDsByAlias[inputAlias]
if !exists {
panic(fmt.Sprintf("unknown input alias: %s", inputAlias))
}

mockedInputs = append(mockedInputs, NewMockedInput(outputID))
}

tx := NewMockedTransaction(mockedInputs, outputCount)
tx.ID().RegisterAlias(txAlias)
t.transactionsByAlias[txAlias] = tx

for i := uint16(0); i < outputCount; i++ {
outputID := utxo.NewOutputID(tx.ID(), i, []byte(""))
outputAlias := txAlias + "." + strconv.Itoa(int(i))

outputID.RegisterAlias(outputAlias)
t.outputIDsByAlias[outputAlias] = outputID
}
}

func (t *TestFramework) IssueTransaction(txAlias string) (err error) {
transaction, exists := t.transactionsByAlias[txAlias]
if !exists {
panic(fmt.Sprintf("unknown transaction alias: %s", txAlias))
}

return t.Ledger.StoreAndProcessTransaction(transaction)
}

// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////

// region MockedInput //////////////////////////////////////////////////////////////////////////////////////////////////

type MockedInput struct {
Expand Down Expand Up @@ -211,8 +274,20 @@ func (m *MockedTransaction) Bytes() []byte {
}

func (m *MockedTransaction) String() (humanReadable string) {
inputIDs := NewOutputIDs()
for _, input := range m.Inputs() {
inputIDs.Add(input.(*MockedInput).outputID)
}

outputIDs := NewOutputIDs()
for i := uint16(0); i < m.outputCount; i++ {
outputIDs.Add(utxo.NewOutputID(m.ID(), i, []byte("")))
}

return stringify.Struct("MockedTransaction",
stringify.StructField("id", m.ID()),
stringify.StructField("inputs", inputIDs),
stringify.StructField("outputs", outputIDs),
)
}

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/refactored/utxo/outputid.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (o OutputID) String() (humanReadable string) {
defer _outputIDAliasesMutex.RUnlock()

if alias, exists := _outputIDAliases[o]; exists {
return "OutputID(" + alias + ")"
return alias
}

return "OutputID(" + base58.Encode(o[:]) + ")"
Expand Down
6 changes: 5 additions & 1 deletion packages/refactored/utxo/outputids.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (o OutputIDs) FromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (err er
return nil
}

func (o OutputIDs) IsEmpty() (empty bool) {
return o.OrderedMap == nil || o.OrderedMap.Size() == 0
}

func (o OutputIDs) Add(outputID OutputID) (added bool) {
return o.Set(outputID, types.Void)
}
Expand Down Expand Up @@ -136,7 +140,7 @@ func (o OutputIDs) Bytes() (serialized []byte) {
}

func (o OutputIDs) String() (humanReadable string) {
elementStrings := generics.Map(o.Slice(), OutputID.Base58)
elementStrings := generics.Map(o.Slice(), OutputID.String)
if len(elementStrings) == 0 {
return "OutputIDs()"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/refactored/utxo/transactionid.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (t TransactionID) String() string {
defer _transactionIDAliasesMutex.RUnlock()

if alias, exists := _transactionIDAliases[t]; exists {
return "TransactionID(" + alias + ")"
return alias
}

return "TransactionID(" + t.Base58() + ")"
Expand Down

0 comments on commit 2819366

Please sign in to comment.