Skip to content
Snippets Groups Projects
Commit a4af68b1 authored by Wolfgang Welz's avatar Wolfgang Welz
Browse files

Add PoW support for MetaTransaction

parent 58924245
No related branches found
No related tags found
No related merge requests found
package meta_transaction package meta_transaction
import ( import (
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/trinary" "github.com/iotaledger/iota.go/trinary"
) )
...@@ -12,6 +13,7 @@ const ( ...@@ -12,6 +13,7 @@ const (
TAIL_OFFSET = HEAD_END TAIL_OFFSET = HEAD_END
TRANSACTION_TYPE_OFFSET = TAIL_END TRANSACTION_TYPE_OFFSET = TAIL_END
DATA_OFFSET = TRANSACTION_TYPE_END DATA_OFFSET = TRANSACTION_TYPE_END
NONCE_OFFSET = DATA_END
SHARD_MARKER_SIZE = 11 SHARD_MARKER_SIZE = 11
TRUNK_TRANSACTION_HASH_SIZE = 243 TRUNK_TRANSACTION_HASH_SIZE = 243
...@@ -20,6 +22,7 @@ const ( ...@@ -20,6 +22,7 @@ const (
TAIL_SIZE = 1 TAIL_SIZE = 1
TRANSACTION_TYPE_SIZE = 8 TRANSACTION_TYPE_SIZE = 8
DATA_SIZE = 6993 DATA_SIZE = 6993
NONCE_SIZE = consts.NonceTrinarySize
SHARD_MARKER_END = SHARD_MARKER_OFFSET + SHARD_MARKER_SIZE SHARD_MARKER_END = SHARD_MARKER_OFFSET + SHARD_MARKER_SIZE
TRUNK_TRANSACTION_HASH_END = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE TRUNK_TRANSACTION_HASH_END = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE
...@@ -28,8 +31,9 @@ const ( ...@@ -28,8 +31,9 @@ const (
TAIL_END = TAIL_OFFSET + TAIL_SIZE TAIL_END = TAIL_OFFSET + TAIL_SIZE
TRANSACTION_TYPE_END = TRANSACTION_TYPE_OFFSET + TRANSACTION_TYPE_SIZE TRANSACTION_TYPE_END = TRANSACTION_TYPE_OFFSET + TRANSACTION_TYPE_SIZE
DATA_END = DATA_OFFSET + DATA_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") BRANCH_NULL_HASH = trinary.Trytes("999999999999999999999999999999999999999999999999999999999999999999999999999999999")
) )
...@@ -3,8 +3,11 @@ package meta_transaction ...@@ -3,8 +3,11 @@ package meta_transaction
import ( import (
"sync" "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/iotaledger/iota.go/trinary"
"github.com/pkg/errors"
) )
type MetaTransaction struct { type MetaTransaction struct {
...@@ -19,6 +22,7 @@ type MetaTransaction struct { ...@@ -19,6 +22,7 @@ type MetaTransaction struct {
transactionType *trinary.Trytes transactionType *trinary.Trytes
data trinary.Trits data trinary.Trits
modified bool modified bool
nonce *trinary.Trytes
hasherMutex sync.RWMutex hasherMutex sync.RWMutex
hashMutex sync.RWMutex hashMutex sync.RWMutex
...@@ -31,6 +35,7 @@ type MetaTransaction struct { ...@@ -31,6 +35,7 @@ type MetaTransaction struct {
dataMutex sync.RWMutex dataMutex sync.RWMutex
bytesMutex sync.RWMutex bytesMutex sync.RWMutex
modifiedMutex sync.RWMutex modifiedMutex sync.RWMutex
nonceMutex sync.RWMutex
trits trinary.Trits trits trinary.Trits
bytes []byte bytes []byte
...@@ -85,7 +90,7 @@ func (this *MetaTransaction) GetHash() (result trinary.Trytes) { ...@@ -85,7 +90,7 @@ func (this *MetaTransaction) GetHash() (result trinary.Trytes) {
defer this.hashMutex.Unlock() defer this.hashMutex.Unlock()
if this.hash == nil { if this.hash == nil {
this.hasherMutex.Lock() this.hasherMutex.Lock()
this.parseHashRelatedDetails() this.computeHashDetails()
this.hasherMutex.Unlock() this.hasherMutex.Unlock()
} }
} else { } else {
...@@ -106,7 +111,7 @@ func (this *MetaTransaction) GetWeightMagnitude() (result int) { ...@@ -106,7 +111,7 @@ func (this *MetaTransaction) GetWeightMagnitude() (result int) {
defer this.hashMutex.Unlock() defer this.hashMutex.Unlock()
if this.hash == nil { if this.hash == nil {
this.hasherMutex.Lock() this.hasherMutex.Lock()
this.parseHashRelatedDetails() this.computeHashDetails()
this.hasherMutex.Unlock() this.hasherMutex.Unlock()
} }
} else { } else {
...@@ -118,9 +123,26 @@ func (this *MetaTransaction) GetWeightMagnitude() (result int) { ...@@ -118,9 +123,26 @@ func (this *MetaTransaction) GetWeightMagnitude() (result int) {
return 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) // hashes the transaction using curl (without locking - internal usage)
func (this *MetaTransaction) parseHashRelatedDetails() { func (this *MetaTransaction) computeHashDetails() {
hashTrits := curl.CURLP81.Hash(this.trits) hashTrits, err := curl.HashTrits(this.getHashEssence())
if err != nil {
panic(err)
}
hashTrytes := trinary.MustTritsToTrytes(hashTrits) hashTrytes := trinary.MustTritsToTrytes(hashTrits)
this.hash = &hashTrytes this.hash = &hashTrytes
...@@ -466,6 +488,49 @@ func (this *MetaTransaction) GetBytes() (result []byte) { ...@@ -466,6 +488,49 @@ func (this *MetaTransaction) GetBytes() (result []byte) {
return 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) // returns true if the transaction contains unsaved changes (supports concurrency)
func (this *MetaTransaction) GetModified() bool { func (this *MetaTransaction) GetModified() bool {
this.modifiedMutex.RLock() this.modifiedMutex.RLock()
...@@ -481,3 +546,18 @@ func (this *MetaTransaction) SetModified(modified bool) { ...@@ -481,3 +546,18 @@ func (this *MetaTransaction) SetModified(modified bool) {
this.modified = modified 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
}
package meta_transaction package meta_transaction
import ( import (
"fmt"
"sync" "sync"
"testing" "testing"
"github.com/iotaledger/iota.go/trinary" "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) { func TestMetaTransaction_SettersGetters(t *testing.T) {
shardMarker := trinary.Trytes("NPHTQORL9XKA") tx := newTestTransaction()
trunkTransactionHash := trinary.Trytes("99999999999999999999999999999999999999999999999999999999999999999999999999999999A")
branchTransactionHash := trinary.Trytes("99999999999999999999999999999999999999999999999999999999999999999999999999999999B") assert.Equal(t, tx.GetWeightMagnitude(), 0)
head := true assert.Equal(t, tx.GetShardMarker(), shardMarker)
tail := true assert.Equal(t, tx.GetTrunkTransactionHash(), trunkTransactionHash)
transactionType := trinary.Trytes("9999999999999999999999") assert.Equal(t, tx.GetBranchTransactionHash(), branchTransactionHash)
assert.Equal(t, tx.IsHead(), head)
transaction := New() assert.Equal(t, tx.IsTail(), tail)
transaction.SetShardMarker(shardMarker) assert.Equal(t, tx.GetTransactionType(), transactionType)
transaction.SetTrunkTransactionHash(trunkTransactionHash) assert.Equal(t, tx.GetHash(), FromBytes(tx.GetBytes()).GetHash())
transaction.SetBranchTransactionHash(branchTransactionHash)
transaction.SetHead(head) assert.EqualValues(t, "KKDVHBENVLQUNO9WOWWEJPBBHUSYRSRKIMZWCFCDB9RYZKYWLAYWRIBRQETBFKE9TIVWQPCKFWAMCLCAV", tx.GetHash())
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())
} }
func BenchmarkMetaTransaction_GetHash(b *testing.B) { func BenchmarkMetaTransaction_GetHash(b *testing.B) {
......
...@@ -10,20 +10,17 @@ const ( ...@@ -10,20 +10,17 @@ const (
ADDRESS_OFFSET = 0 ADDRESS_OFFSET = 0
VALUE_OFFSET = ADDRESS_END VALUE_OFFSET = ADDRESS_END
TIMESTAMP_OFFSET = VALUE_END TIMESTAMP_OFFSET = VALUE_END
NONCE_OFFSET = TIMESTAMP_END SIGNATURE_MESSAGE_FRAGMENT_OFFSET = TIMESTAMP_SIZE
SIGNATURE_MESSAGE_FRAGMENT_OFFSET = NONCE_END
ADDRESS_SIZE = 243 ADDRESS_SIZE = 243
VALUE_SIZE = 81 VALUE_SIZE = 81
TIMESTAMP_SIZE = 27 TIMESTAMP_SIZE = 27
NONCE_SIZE = 81
SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561 SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561
BUNDLE_ESSENCE_SIZE = ADDRESS_SIZE + VALUE_SIZE + SIGNATURE_MESSAGE_FRAGMENT_SIZE BUNDLE_ESSENCE_SIZE = ADDRESS_SIZE + VALUE_SIZE + SIGNATURE_MESSAGE_FRAGMENT_SIZE
ADDRESS_END = ADDRESS_OFFSET + ADDRESS_SIZE ADDRESS_END = ADDRESS_OFFSET + ADDRESS_SIZE
VALUE_END = VALUE_OFFSET + VALUE_SIZE VALUE_END = VALUE_OFFSET + VALUE_SIZE
TIMESTAMP_END = TIMESTAMP_OFFSET + TIMESTAMP_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 SIGNATURE_MESSAGE_FRAGMENT_END = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE
TOTAL_SIZE = SIGNATURE_MESSAGE_FRAGMENT_END TOTAL_SIZE = SIGNATURE_MESSAGE_FRAGMENT_END
......
...@@ -16,8 +16,6 @@ type ValueTransaction struct { ...@@ -16,8 +16,6 @@ type ValueTransaction struct {
valueMutex sync.RWMutex valueMutex sync.RWMutex
timestamp *uint timestamp *uint
timestampMutex sync.RWMutex timestampMutex sync.RWMutex
nonce *trinary.Trytes
nonceMutex sync.RWMutex
signatureMessageFragment *trinary.Trytes signatureMessageFragment *trinary.Trytes
signatureMessageFragmentMutex sync.RWMutex signatureMessageFragmentMutex sync.RWMutex
...@@ -215,53 +213,6 @@ func (this *ValueTransaction) GetBundleEssence(includeSignatureMessageFragment b ...@@ -215,53 +213,6 @@ func (this *ValueTransaction) GetBundleEssence(includeSignatureMessageFragment b
return 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) // getter for the signatureMessageFragmetn (supports concurrency)
func (this *ValueTransaction) GetSignatureMessageFragment() (result trinary.Trytes) { func (this *ValueTransaction) GetSignatureMessageFragment() (result trinary.Trytes) {
this.signatureMessageFragmentMutex.RLock() this.signatureMessageFragmentMutex.RLock()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment