diff --git a/packages/model/meta_transaction/constants.go b/packages/model/meta_transaction/constants.go index 1e5cbdcccfb0e7508fc429cbb41744b7037a0c17..814e958c82ca4e359b1553650fedc71a25d0561f 100644 --- a/packages/model/meta_transaction/constants.go +++ b/packages/model/meta_transaction/constants.go @@ -1,6 +1,7 @@ package meta_transaction import ( + "github.com/iotaledger/iota.go/consts" "github.com/iotaledger/iota.go/trinary" ) @@ -12,6 +13,7 @@ const ( TAIL_OFFSET = HEAD_END TRANSACTION_TYPE_OFFSET = TAIL_END DATA_OFFSET = TRANSACTION_TYPE_END + NONCE_OFFSET = DATA_END SHARD_MARKER_SIZE = 11 TRUNK_TRANSACTION_HASH_SIZE = 243 @@ -20,6 +22,7 @@ const ( TAIL_SIZE = 1 TRANSACTION_TYPE_SIZE = 8 DATA_SIZE = 6993 + NONCE_SIZE = consts.NonceTrinarySize SHARD_MARKER_END = SHARD_MARKER_OFFSET + SHARD_MARKER_SIZE TRUNK_TRANSACTION_HASH_END = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE @@ -28,8 +31,9 @@ const ( TAIL_END = TAIL_OFFSET + TAIL_SIZE TRANSACTION_TYPE_END = TRANSACTION_TYPE_OFFSET + TRANSACTION_TYPE_SIZE DATA_END = DATA_OFFSET + DATA_SIZE + NONCE_END = NONCE_OFFSET + NONCE_SIZE - MARSHALED_TOTAL_SIZE = DATA_END + MARSHALED_TOTAL_SIZE = NONCE_END BRANCH_NULL_HASH = trinary.Trytes("999999999999999999999999999999999999999999999999999999999999999999999999999999999") ) diff --git a/packages/model/meta_transaction/meta_transaction.go b/packages/model/meta_transaction/meta_transaction.go index 575ea6b435bc775e00cc253fa362ce8f3ee95153..c20bab96a35c761f6ee85bb17b8b679113df08dd 100644 --- a/packages/model/meta_transaction/meta_transaction.go +++ b/packages/model/meta_transaction/meta_transaction.go @@ -3,8 +3,11 @@ package meta_transaction import ( "sync" - "github.com/iotaledger/goshimmer/packages/curl" + "github.com/iotaledger/iota.go/consts" + "github.com/iotaledger/iota.go/curl" + "github.com/iotaledger/iota.go/pow" "github.com/iotaledger/iota.go/trinary" + "github.com/pkg/errors" ) type MetaTransaction struct { @@ -19,6 +22,7 @@ type MetaTransaction struct { transactionType *trinary.Trytes data trinary.Trits modified bool + nonce *trinary.Trytes hasherMutex sync.RWMutex hashMutex sync.RWMutex @@ -31,6 +35,7 @@ type MetaTransaction struct { dataMutex sync.RWMutex bytesMutex sync.RWMutex modifiedMutex sync.RWMutex + nonceMutex sync.RWMutex trits trinary.Trits bytes []byte @@ -85,7 +90,7 @@ func (this *MetaTransaction) GetHash() (result trinary.Trytes) { defer this.hashMutex.Unlock() if this.hash == nil { this.hasherMutex.Lock() - this.parseHashRelatedDetails() + this.computeHashDetails() this.hasherMutex.Unlock() } } else { @@ -106,7 +111,7 @@ func (this *MetaTransaction) GetWeightMagnitude() (result int) { defer this.hashMutex.Unlock() if this.hash == nil { this.hasherMutex.Lock() - this.parseHashRelatedDetails() + this.computeHashDetails() this.hasherMutex.Unlock() } } else { @@ -118,9 +123,26 @@ func (this *MetaTransaction) GetWeightMagnitude() (result int) { return } +// returns the trytes that are relevant for the transaction hash +func (this *MetaTransaction) getHashEssence() trinary.Trits { + txTrits := this.trits + + // very dirty hack, to get an iota.go compatible size + if len(txTrits) > consts.TransactionTrinarySize { + panic("transaction too large") + } + essenceTrits := make([]int8, consts.TransactionTrinarySize) + copy(essenceTrits[consts.TransactionTrinarySize-len(txTrits):], txTrits) + + return essenceTrits +} + // hashes the transaction using curl (without locking - internal usage) -func (this *MetaTransaction) parseHashRelatedDetails() { - hashTrits := curl.CURLP81.Hash(this.trits) +func (this *MetaTransaction) computeHashDetails() { + hashTrits, err := curl.HashTrits(this.getHashEssence()) + if err != nil { + panic(err) + } hashTrytes := trinary.MustTritsToTrytes(hashTrits) this.hash = &hashTrytes @@ -466,6 +488,49 @@ func (this *MetaTransaction) GetBytes() (result []byte) { return } +func (this *MetaTransaction) GetNonce() trinary.Trytes { + this.nonceMutex.RLock() + if this.nonce == nil { + this.nonceMutex.RUnlock() + this.nonceMutex.Lock() + defer this.nonceMutex.Unlock() + if this.nonce == nil { + nonce := trinary.MustTritsToTrytes(this.trits[NONCE_OFFSET:NONCE_END]) + + this.nonce = &nonce + } + } else { + defer this.nonceMutex.RUnlock() + } + + return *this.nonce +} + +func (this *MetaTransaction) SetNonce(nonce trinary.Trytes) bool { + this.nonceMutex.RLock() + if this.nonce == nil || *this.nonce != nonce { + this.nonceMutex.RUnlock() + this.nonceMutex.Lock() + defer this.nonceMutex.Unlock() + if this.nonce == nil || *this.nonce != nonce { + this.nonce = &nonce + + this.hasherMutex.RLock() + copy(this.trits[NONCE_OFFSET:NONCE_END], trinary.MustTrytesToTrits(nonce)[:NONCE_SIZE]) + this.hasherMutex.RUnlock() + + this.SetModified(true) + this.ReHash() + + return true + } + } else { + this.nonceMutex.RUnlock() + } + + return false +} + // returns true if the transaction contains unsaved changes (supports concurrency) func (this *MetaTransaction) GetModified() bool { this.modifiedMutex.RLock() @@ -481,3 +546,18 @@ func (this *MetaTransaction) SetModified(modified bool) { this.modified = modified } + +func (this *MetaTransaction) DoProofOfWork(mwm int) error { + this.hasherMutex.Lock() + powTrytes := trinary.MustTritsToTrytes(this.getHashEssence()) + _, pow := pow.GetFastestProofOfWorkImpl() + nonce, err := pow(powTrytes, mwm) + this.hasherMutex.Unlock() + + if err != nil { + return errors.Wrap(err, "PoW failed") + } + this.SetNonce(nonce) + + return nil +} diff --git a/packages/model/meta_transaction/meta_transaction_test.go b/packages/model/meta_transaction/meta_transaction_test.go index 2ba055b76a74928485bfd0b11a9d959d68bd47ac..fa6ec565255b903bd4e917b631873c54696230ba 100644 --- a/packages/model/meta_transaction/meta_transaction_test.go +++ b/packages/model/meta_transaction/meta_transaction_test.go @@ -1,40 +1,55 @@ package meta_transaction import ( - "fmt" "sync" "testing" "github.com/iotaledger/iota.go/trinary" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) +const ( + shardMarker = trinary.Trytes("NPHTQORL9XKA") + trunkTransactionHash = trinary.Trytes("99999999999999999999999999999999999999999999999999999999999999999999999999999999A") + branchTransactionHash = trinary.Trytes("99999999999999999999999999999999999999999999999999999999999999999999999999999999B") + head = true + tail = true + transactionType = trinary.Trytes("9999999999999999999999") +) + +func newTestTransaction() *MetaTransaction { + tx := New() + tx.SetShardMarker(shardMarker) + tx.SetTrunkTransactionHash(trunkTransactionHash) + tx.SetBranchTransactionHash(branchTransactionHash) + tx.SetHead(head) + tx.SetTail(tail) + tx.SetTransactionType(transactionType) + + return tx +} + +func TestDoPow(t *testing.T) { + tx := newTestTransaction() + require.NoError(t, tx.DoProofOfWork(10)) + + assert.GreaterOrEqual(t, tx.GetWeightMagnitude(), 10) +} + func TestMetaTransaction_SettersGetters(t *testing.T) { - shardMarker := trinary.Trytes("NPHTQORL9XKA") - trunkTransactionHash := trinary.Trytes("99999999999999999999999999999999999999999999999999999999999999999999999999999999A") - branchTransactionHash := trinary.Trytes("99999999999999999999999999999999999999999999999999999999999999999999999999999999B") - head := true - tail := true - transactionType := trinary.Trytes("9999999999999999999999") - - transaction := New() - transaction.SetShardMarker(shardMarker) - transaction.SetTrunkTransactionHash(trunkTransactionHash) - transaction.SetBranchTransactionHash(branchTransactionHash) - transaction.SetHead(head) - transaction.SetTail(tail) - transaction.SetTransactionType(transactionType) - - assert.Equal(t, transaction.GetWeightMagnitude(), 0) - assert.Equal(t, transaction.GetShardMarker(), shardMarker) - assert.Equal(t, transaction.GetTrunkTransactionHash(), trunkTransactionHash) - assert.Equal(t, transaction.GetBranchTransactionHash(), branchTransactionHash) - assert.Equal(t, transaction.IsHead(), head) - assert.Equal(t, transaction.IsTail(), tail) - assert.Equal(t, transaction.GetTransactionType(), transactionType) - assert.Equal(t, transaction.GetHash(), FromBytes(transaction.GetBytes()).GetHash()) - - fmt.Println(transaction.GetHash()) + tx := newTestTransaction() + + assert.Equal(t, tx.GetWeightMagnitude(), 0) + assert.Equal(t, tx.GetShardMarker(), shardMarker) + assert.Equal(t, tx.GetTrunkTransactionHash(), trunkTransactionHash) + assert.Equal(t, tx.GetBranchTransactionHash(), branchTransactionHash) + assert.Equal(t, tx.IsHead(), head) + assert.Equal(t, tx.IsTail(), tail) + assert.Equal(t, tx.GetTransactionType(), transactionType) + assert.Equal(t, tx.GetHash(), FromBytes(tx.GetBytes()).GetHash()) + + assert.EqualValues(t, "KKDVHBENVLQUNO9WOWWEJPBBHUSYRSRKIMZWCFCDB9RYZKYWLAYWRIBRQETBFKE9TIVWQPCKFWAMCLCAV", tx.GetHash()) } func BenchmarkMetaTransaction_GetHash(b *testing.B) { diff --git a/packages/model/value_transaction/constants.go b/packages/model/value_transaction/constants.go index cc2175fd49fa7f98581dc7321a6aca7c325adc5f..c602d1ea6d3870cbc17160914f63c6af1f234eca 100644 --- a/packages/model/value_transaction/constants.go +++ b/packages/model/value_transaction/constants.go @@ -10,20 +10,17 @@ const ( ADDRESS_OFFSET = 0 VALUE_OFFSET = ADDRESS_END TIMESTAMP_OFFSET = VALUE_END - NONCE_OFFSET = TIMESTAMP_END - SIGNATURE_MESSAGE_FRAGMENT_OFFSET = NONCE_END + SIGNATURE_MESSAGE_FRAGMENT_OFFSET = TIMESTAMP_SIZE ADDRESS_SIZE = 243 VALUE_SIZE = 81 TIMESTAMP_SIZE = 27 - NONCE_SIZE = 81 SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561 BUNDLE_ESSENCE_SIZE = ADDRESS_SIZE + VALUE_SIZE + SIGNATURE_MESSAGE_FRAGMENT_SIZE ADDRESS_END = ADDRESS_OFFSET + ADDRESS_SIZE VALUE_END = VALUE_OFFSET + VALUE_SIZE TIMESTAMP_END = TIMESTAMP_OFFSET + TIMESTAMP_SIZE - NONCE_END = NONCE_OFFSET + NONCE_SIZE SIGNATURE_MESSAGE_FRAGMENT_END = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE TOTAL_SIZE = SIGNATURE_MESSAGE_FRAGMENT_END diff --git a/packages/model/value_transaction/value_transaction.go b/packages/model/value_transaction/value_transaction.go index e4972d271af93578c7d43fb147fddabcdf915ba5..b42a647348d7b28ec86b8a8ed79ac2506b8863b4 100644 --- a/packages/model/value_transaction/value_transaction.go +++ b/packages/model/value_transaction/value_transaction.go @@ -16,8 +16,6 @@ type ValueTransaction struct { valueMutex sync.RWMutex timestamp *uint timestampMutex sync.RWMutex - nonce *trinary.Trytes - nonceMutex sync.RWMutex signatureMessageFragment *trinary.Trytes signatureMessageFragmentMutex sync.RWMutex @@ -215,53 +213,6 @@ func (this *ValueTransaction) GetBundleEssence(includeSignatureMessageFragment b return } -// getter for the nonce (supports concurrency) -func (this *ValueTransaction) GetNonce() (result trinary.Trytes) { - this.nonceMutex.RLock() - if this.nonce == nil { - this.nonceMutex.RUnlock() - this.nonceMutex.Lock() - defer this.nonceMutex.Unlock() - if this.nonce == nil { - nonce := trinary.MustTritsToTrytes(this.trits[NONCE_OFFSET:NONCE_END]) - - this.nonce = &nonce - } - } else { - defer this.nonceMutex.RUnlock() - } - - result = *this.nonce - - return -} - -// setter for the nonce (supports concurrency) -func (this *ValueTransaction) SetNonce(nonce trinary.Trytes) bool { - this.nonceMutex.RLock() - if this.nonce == nil || *this.nonce != nonce { - this.nonceMutex.RUnlock() - this.nonceMutex.Lock() - defer this.nonceMutex.Unlock() - if this.nonce == nil || *this.nonce != nonce { - this.nonce = &nonce - - this.BlockHasher() - copy(this.trits[NONCE_OFFSET:NONCE_END], trinary.MustTrytesToTrits(nonce)[:NONCE_SIZE]) - this.UnblockHasher() - - this.SetModified(true) - this.ReHash() - - return true - } - } else { - this.nonceMutex.RUnlock() - } - - return false -} - // getter for the signatureMessageFragmetn (supports concurrency) func (this *ValueTransaction) GetSignatureMessageFragment() (result trinary.Trytes) { this.signatureMessageFragmentMutex.RLock()