Skip to content
This repository has been archived by the owner on Jun 7, 2023. It is now read-only.

Commit

Permalink
Merge pull request #13 from iotaledger/release/1.1.0
Browse files Browse the repository at this point in the history
PyOTA-PoW v1.1.0
  • Loading branch information
lzpap authored Nov 5, 2019
2 parents 5ab966e + c43808f commit 18a0977
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 135 deletions.
56 changes: 0 additions & 56 deletions examples/with_entangled.py

This file was deleted.

25 changes: 25 additions & 0 deletions init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,31 @@ rm -f pow/libccurl.so
# Get current working directory
WD=$(pwd)

# By default, ccurl lib compiles with debug symbols, that we don't necessarly
# want to see when using the interface. Remove them before building.

# Definition of a DEBUG symbol
pattern='#ifndef DEBUG'

# Find files that define DEBUG symbols in ccurl repo
result=$(grep -rnw 'ccurl_repo/' -e "$pattern" -l)

# Result is not empty
if [ -n "$result" ]; then
# Transform cmd output to array
readarray -t files <<<$result

# Go thorugh the files and delete line with pattern + 2 follwing lines
# A definition in c looks like this:
# #ifndef DEBUG
# define DEBUG
# endif
for i in "${files[@]}"; do
echo "Removing DEBUG symbols from $i"
sed -i -e "/$pattern/,+2d" $i
done
fi

# Bulding using cmake
echo "Building ccurl library with cmake..."
cd ccurl_repo/ccurl && mkdir -p build && cd build && cmake .. && cmake --build .
Expand Down
112 changes: 77 additions & 35 deletions pow/ccurl_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import math
import time
from iota.exceptions import with_context
import logging
from sys import stderr

from pkg_resources import resource_filename
libccurl_path = resource_filename("pow","libccurl.so")
Expand All @@ -24,6 +26,10 @@
_libccurl.ccurl_digest_transaction.restype = POINTER(c_char)
_libccurl.ccurl_digest_transaction.argtypes = [c_char_p]

# Create a logger
logger = logging.getLogger(__name__)
logging.basicConfig(stream=stderr, level=logging.INFO)

def check_tx_trytes_length(trytes):
"""
Checks if trytes are exactly one transaction in length.
Expand Down Expand Up @@ -66,7 +72,7 @@ def get_powed_tx_trytes( trytes, mwm ):
def get_hash_trytes(trytes):
"""
Calls `ccurl_digest_transaction` function from ccurl
library to calculate `rtansaction hash`. Returns the
library to calculate `transaction hash`. Returns the
81 trytes long hash in unicode string format.
"""
# Make sure we supply the right size of tx trytes to ccurl
Expand Down Expand Up @@ -111,41 +117,77 @@ def attach_to_tangle(bundle_trytes, # Iterable[TryteString]
# Construct bundle object
bundle = Bundle.from_tryte_strings(bundle_trytes)

# reversed, beause pyota bundles look like [...tx2,tx1,tx0]
# and we need the tail tx first (tx0)
# Used for checking hash
trailing_zeros = [0] * mwm

# reversed, beause pyota bundles look like [tx0,tx1,...]
# and we need the head (last) tx first
for txn in reversed(bundle.transactions):
txn.attachment_timestamp = get_current_ms()
txn.attachment_timestamp_upper_bound = (math.pow(3,27) - 1) // 2

if (not previoustx): # this is the tail transaction
if txn.current_index == txn.last_index:
txn.branch_transaction_hash = branch_transaction_hash
txn.trunk_transaction_hash = trunk_transaction_hash
# Ccurl lib sometimes needs a kick to return the correct powed trytes.
# We can check the correctness by examining trailing zeros of the
# transaction hash. If that fails, we try calculating the pow again.
# Use `max_iter` to prevent infinite loop. Calculation error appears
# rarely, and usually the second try yields correct result. If we reach
# `max_iter`, we raise a ValueError.
max_iter = 5
i = 0

# If calculation is successful, we break out from the while loop.
while i != max_iter:
# Fill timestamps
txn.attachment_timestamp = get_current_ms()
txn.attachment_timestamp_upper_bound = (math.pow(3,27) - 1) // 2

# Determine correct trunk and branch transaction
if (not previoustx): # this is the head transaction
if txn.current_index == txn.last_index:
txn.branch_transaction_hash = branch_transaction_hash
txn.trunk_transaction_hash = trunk_transaction_hash
else:
raise ValueError('Head transaction is inconsistent in bundle')

else: # It is not the head transaction
txn.branch_transaction_hash = trunk_transaction_hash
txn.trunk_transaction_hash = previoustx # the previous transaction

# Let's do the pow locally
txn_string = txn.as_tryte_string().__str__()
# returns a python unicode string
powed_txn_string = get_powed_tx_trytes(txn_string, mwm)
# construct trytestring from python string
powed_txn_trytes = TryteString(powed_txn_string)

# Create powed txn object
# This method calculates the hash for the transaction
powed_txn = Transaction.from_tryte_string(
trytes=powed_txn_trytes
)
previoustx = powed_txn.hash
# put that back in the bundle
bundle.transactions[txn.current_index] = powed_txn

# Check for inconsistency in hash
hash_trits = powed_txn.hash.as_trits()
if hash_trits[-mwm:] == trailing_zeros:
# We are good to go, exit from while loop
break
else:
raise ValueError('Tail transaction is inconsistent in bundle')

else: # It is not a tail transaction
txn.branch_transaction_hash = trunk_transaction_hash
txn.trunk_transaction_hash = previoustx # the previous transaction

# Let's do the pow locally
txn_string = txn.as_tryte_string().__str__()
# returns a python unicode string
powed_txn_string = get_powed_tx_trytes(txn_string, mwm)
# construct trytestring from python string
powed_txn_trytes = TryteString(powed_txn_string)
# compute transaction hash
hash_string = get_hash_trytes(powed_txn_string)
hash_trytes = TryteString(hash_string)
hash_= TransactionHash(hash_trytes)

# Create powed txn object
powed_txn = Transaction.from_tryte_string(
trytes=powed_txn_trytes,
hash_=hash_
)
i = i + 1
logger.info('Ooops, wrong hash detected in try'
' #{rounds}. Recalculating pow... '.format(rounds= i))

# Something really bad happened
if i == max_iter:
raise with_context(
exc=ValueError('PoW calculation failed for {max_iter} times.'
' Make sure that the transaction is valid: {tx}'.format(
max_iter=max_iter,
tx=powed_txn.as_json_compatible()
)
),
context={
'original': txn,
},
)

previoustx = powed_txn.hash
# put that back in the bundle
bundle.transactions[txn.current_index] = powed_txn
return bundle.as_tryte_strings()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
name = 'PyOTA-PoW',
description = 'Ccurl PoW Interface for PyOTA',
url = 'https://github.com/iotaledger/ccurl.interface.py',
version = '1.0.2',
version = '1.1.0',

long_description = long_description,
packages=['pow'],
Expand Down
Loading

0 comments on commit 18a0977

Please sign in to comment.