diff --git a/packages/ternary/ternary.go b/packages/ternary/ternary.go index 3b8fa42607afa6f77268b52050db0d3eaec06ab4..1e4ba027a57cbf2217ab7ed5d4346384b8cd30e2 100644 --- a/packages/ternary/ternary.go +++ b/packages/ternary/ternary.go @@ -22,7 +22,7 @@ func (trinary Trinary) CastToBytes() []byte { } func (trinary Trinary) ToTrits() Trits { - trits := make(Trits, len(trinary)*3) + trits := make(Trits, 0, len(trinary)*NUMBER_OF_TRITS_IN_A_TRYTE) for _, char := range trinary { trits = append(trits, TRYTES_TO_TRITS_MAP[char]...) } @@ -57,7 +57,7 @@ func (this Trits) ToBytes() []byte { func (this Trits) TrailingZeroes() int { zeros := 0 index := len(this) - 1 - for this[index] == 0 { + for index >= 0 && this[index] == 0 { zeros++ index-- diff --git a/plugins/tangle/approvers_test.go b/plugins/tangle/approvers_test.go index fffd889ab3ebf6f10cc7fab5497f904e5701ea1e..b7e4b684e65b947bc14a1df4a4a4203434bb2baa 100644 --- a/plugins/tangle/approvers_test.go +++ b/plugins/tangle/approvers_test.go @@ -1,73 +1,42 @@ package tangle import ( - "fmt" + "sync" "testing" - "time" "github.com/iotaledger/goshimmer/packages/events" "github.com/iotaledger/goshimmer/packages/ternary" - "github.com/iotaledger/goshimmer/packages/transaction" "github.com/iotaledger/goshimmer/plugins/gossip" ) -func TestGetApprovers(t *testing.T) { - configureDatabase(nil) - - approvers, err := GetApprovers(ternary.Trinary("AA"), NewApprovers) - - approvers.Add(ternary.Trinary("FF")) - - fmt.Println(approvers) - fmt.Println(err) - - approvers1, err1 := GetApprovers(ternary.Trinary("AA")) - - fmt.Println(approvers1) - fmt.Println(err1) -} - func TestSolidifier(t *testing.T) { + // initialize plugin configureDatabase(nil) configureSolidifier(nil) - txData := make([]byte, 1572) - txData[1571] = 1 - - tx := transaction.FromBytes(txData) - - txData[1571] = 2 - tx1 := transaction.FromBytes(txData) - tx1.BranchTransactionHash = tx.Hash - - txData[1571] = 3 - tx2 := transaction.FromBytes(txData) - tx2.BranchTransactionHash = tx1.Hash - - txData[1571] = 4 - tx3 := transaction.FromBytes(txData) - tx3.BranchTransactionHash = tx2.Hash - - fmt.Println(tx.Hash.ToString()) - fmt.Println(tx1.Hash.ToString()) - fmt.Println(tx2.Hash.ToString()) - fmt.Println(tx3.Hash.ToString()) - - fmt.Println("============") - + // create transactions and chain them together + transaction1 := NewTransaction(nil) + transaction1.SetNonce(ternary.Trinary("99999999999999999999999999A")) + transaction2 := NewTransaction(nil) + transaction2.SetBranchTransactionHash(transaction1.GetHash()) + transaction3 := NewTransaction(nil) + transaction3.SetBranchTransactionHash(transaction2.GetHash()) + transaction4 := NewTransaction(nil) + transaction4.SetBranchTransactionHash(transaction3.GetHash()) + + // setup event handlers + var wg sync.WaitGroup Events.TransactionSolid.Attach(events.NewClosure(func(transaction *Transaction) { - fmt.Println("SOLID: " + transaction.GetHash()) + wg.Done() })) - gossip.Events.ReceiveTransaction.Trigger(tx) - gossip.Events.ReceiveTransaction.Trigger(tx1) - gossip.Events.ReceiveTransaction.Trigger(tx3) - - fmt.Println("...") - - time.Sleep(1 * time.Second) - - gossip.Events.ReceiveTransaction.Trigger(tx2) + // issue transactions + wg.Add(4) + gossip.Events.ReceiveTransaction.Trigger(transaction1.Flush()) + gossip.Events.ReceiveTransaction.Trigger(transaction2.Flush()) + gossip.Events.ReceiveTransaction.Trigger(transaction3.Flush()) + gossip.Events.ReceiveTransaction.Trigger(transaction4.Flush()) - time.Sleep(1 * time.Second) + // wait until all are solid + wg.Wait() } diff --git a/plugins/tangle/transaction.go b/plugins/tangle/transaction.go index 08f9c3512658755dc49a2b774eacbfc4f99f823b..6ee98b52d8a3597f9e25e34b990f13eeeac32ffd 100644 --- a/plugins/tangle/transaction.go +++ b/plugins/tangle/transaction.go @@ -1,8 +1,10 @@ package tangle import ( + "math" "sync" + "github.com/iotaledger/goshimmer/packages/curl" "github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/ternary" "github.com/iotaledger/goshimmer/packages/transaction" @@ -48,6 +50,10 @@ type Transaction struct { } func NewTransaction(rawTransaction *transaction.Transaction) *Transaction { + if rawTransaction == nil { + rawTransaction = transaction.FromBytes(make([]byte, int(math.Ceil(float64(transaction.MARSHALLED_TOTAL_SIZE)/ternary.NUMBER_OF_TRITS_IN_A_BYTE)))) + } + return &Transaction{rawTransaction: rawTransaction} } @@ -123,6 +129,10 @@ func (transaction *Transaction) ParseHash() ternary.Trinary { // parses the hash from the underlying raw transaction (without locking - internal usage) func (transaction *Transaction) parseHash() (result ternary.Trinary) { + if transaction.modified { + transaction.Flush() + } + result = transaction.rawTransaction.Hash.ToTrinary() transaction.hash = &result @@ -500,7 +510,7 @@ func (transaction *Transaction) SetBranchTransactionHash(branchTransactionHash t transaction.branchTransactionHashMutex.Lock() defer transaction.branchTransactionHashMutex.Unlock() if transaction.branchTransactionHash == nil || *transaction.branchTransactionHash != branchTransactionHash { - *transaction.branchTransactionHash = branchTransactionHash + transaction.branchTransactionHash = &branchTransactionHash transaction.SetModified(true) } @@ -600,7 +610,7 @@ func (transaction *Transaction) SetNonce(nonce ternary.Trinary) { transaction.nonceMutex.Lock() defer transaction.nonceMutex.Unlock() if transaction.nonce == nil || *transaction.nonce != nonce { - *transaction.nonce = nonce + transaction.nonce = &nonce transaction.SetModified(true) } @@ -618,8 +628,10 @@ func (transaction *Transaction) ParseNonce() ternary.Trinary { } // parses the nonce from the underlying raw transaction (without locking - internal usage) -func (transaction *Transaction) parseNonce() ternary.Trinary { - *transaction.nonce = transaction.rawTransaction.Nonce.ToTrinary() +func (transaction *Transaction) parseNonce() (result ternary.Trinary) { + result = transaction.rawTransaction.Nonce.ToTrinary() + + transaction.nonce = &result return *transaction.nonce } @@ -644,6 +656,20 @@ func (transaction *Transaction) SetModified(modified bool) { // region database functions /////////////////////////////////////////////////////////////////////////////////////////// +// Applies the current values to the +func (this *Transaction) Flush() *transaction.Transaction { + if this.branchTransactionHash != nil { + copy(this.rawTransaction.Trits[transaction.BRANCH_TRANSACTION_HASH_OFFSET:transaction.BRANCH_TRANSACTION_HASH_END], this.branchTransactionHash.ToTrits()[:transaction.BRANCH_TRANSACTION_HASH_SIZE]) + } + if this.nonce != nil { + copy(this.rawTransaction.Trits[transaction.NONCE_OFFSET:transaction.NONCE_END], this.nonce.ToTrits()[:transaction.NONCE_SIZE]) + } + + this.rawTransaction.Hash = <-curl.CURLP81.Hash(this.rawTransaction.Trits) + + return this.rawTransaction +} + func (transaction *Transaction) Store() errors.IdentifiableError { if err := transactionDatabase.Set(transaction.rawTransaction.Hash.ToBytes(), transaction.rawTransaction.Bytes); err != nil { return ErrDatabaseError.Derive(err, "failed to store the transaction")