Hyperledger Iroha - MST_EXPIRED error when running example code - hyperledger

Started an Iroha node docker container, everything works fine when I submit transaction via command line tool. But when I tried to run the example code (both java and node versions) encountered an error with status MST_EXPIRED.
mst_enabled config is false and nothing is changed in the default example code.
Output log of the example (java version, same for node):
Hash of the transaction:
a7ea8d22ed0ec3b0426e58503d260cc98c186dc7d81cdb8c6c02c3ad5c709b27
Status of the transaction is: MST_EXPIRED
Your transaction wasn't committed
Output log of Iroha container:
[2018-11-14 13:13:43.918089622][th:40][info] TxProcessor handle batch
[2018-11-14 13:13:43.918116295][th:40][info] TxProcessor propagating batch to PCS
[2018-11-14 13:13:43.918169891][th:40][info] PCS propagate batch
[2018-11-14 13:13:43.918177499][th:40][info] OrderingGate propagate batch, account_id: admin#test
[2018-11-14 13:13:43.918186593][th:40][info] AsyncGrpcClient Propagate transaction batch (on transport)
[2018-11-14 13:13:43.918550129][th:38][info] AsyncGrpcClient OrderingServiceTransportGrpc::onBatch
[2018-11-14 13:13:43.918591326][th:38][info] OrderingServiceImpl Queue size is 1
[2018-11-14 13:13:43.941924884][th:32][info] OrderingServiceImpl Start proposal generation
[2018-11-14 13:13:43.942369144][th:32][info] StorageImpl create ordering service persistent state
[2018-11-14 13:13:43.942390879][th:32][info] PostgresOrderingServicePersistentState Save proposal_height in ordering_service_state 4
[2018-11-14 13:13:43.969640150][th:32][info] AsyncGrpcClient OrderingServiceTransportGrpc::publishProposal
[2018-11-14 13:13:43.970038906][th:38][info] AsyncGrpcClient receive proposal
[2018-11-14 13:13:43.970410273][th:38][info] AsyncGrpcClient transactions in proposal: 1
[2018-11-14 13:13:43.970426458][th:38][info] OrderingGate Received new proposal, height: 3
[2018-11-14 13:13:43.970459548][th:34][info] OrderingGate Pass the proposal to pipeline height 3
[2018-11-14 13:13:43.970473925][th:34][info] Simulator process proposal
[2018-11-14 13:13:43.970904726][th:34][info] SFV transactions in proposal: 1
[2018-11-14 13:13:43.973084613][th:34][info] SFV transactions in verified proposal: 1
[2018-11-14 13:13:43.973217877][th:34][info] Simulator process verified proposal
[2018-11-14 13:13:43.973431873][th:34][info] YacGate vote for block (d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e, Hash: [d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e ])
[2018-11-14 13:13:43.973935258][th:34][info] YAC Order for voting: {0.0.0.0:10001}
[2018-11-14 13:13:43.974084224][th:34][info] YAC Vote for round (3, 1), hash (d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e, d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e)
[2018-11-14 13:13:43.974220122][th:34][info] AsyncGrpcClient Send votes bundle[size=1] to 0.0.0.0:10001
[2018-11-14 13:13:43.974269361][th:34][info] TxProcessor on stateful validation success: a7ea8d22ed0ec3b0426e58503d260cc98c186dc7d81cdb8c6c02c3ad5c709b27
[2018-11-14 13:13:43.974313290][th:34][info] IROHAD ~~~~~~~~~| PROPOSAL ^_^ |~~~~~~~~~
[2018-11-14 13:13:43.974463906][th:42][info] AsyncGrpcClient Receive votes[size=1] from ipv4:127.0.0.1:39408
[2018-11-14 13:13:43.974669567][th:42][info] ProposalStorage Vote with round [3, 1] and hashes [d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e, d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e] looks valid
[2018-11-14 13:13:43.974679308][th:42][info] YacBlockStorage Vote with rounds (3, 1) and hashes (d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e, d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e) inserted
[2018-11-14 13:13:43.974684799][th:42][info] YacBlockStorage Votes in storage [1/1]
[2018-11-14 13:13:43.974691104][th:42][info] YAC Propagate state (3, 1) to whole network
[2018-11-14 13:13:43.974759898][th:42][info] AsyncGrpcClient Send votes bundle[size=1] to 0.0.0.0:10001
[2018-11-14 13:13:43.974932023][th:38][info] AsyncGrpcClient Receive votes[size=1] from ipv4:127.0.0.1:39408
[2018-11-14 13:13:43.975272280][th:38][info] YAC Pass outcome for (3, 1) to pipeline
[2018-11-14 13:13:43.975306433][th:38][info] YacGate consensus: commit top block: height 3, hash d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e
[2018-11-14 13:13:43.975316694][th:38][info] synchronizer processing commit
[2018-11-14 13:13:43.975782890][th:38][info] ChainValidator validate chain...
[2018-11-14 13:13:43.975896120][th:38][info] MutableStorage Applying block: height 3, hash d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e
[2018-11-14 13:13:43.975907314][th:38][info] ChainValidator validate block: height 3, hash d152f85b155a8e9a87e4ab0ab0a8e3c3b54a731491e29d59e83b922ffae5532e
[2018-11-14 13:13:43.985618510][th:38][info] IROHAD ~~~~~~~~~| COMMIT =^._.^= |~~~~~~~~~
[2018-11-14 13:13:43.985661598][th:38][info] TxProcessor on commit committed: a7ea8d22ed0ec3b0426e58503d260cc98c186dc7d81cdb8c6c02c3ad5c709b27
However it seems that the asset has been created, but the query returns error.
Anyone can help? It seems that I'm the only one who encountered this problem!
Thanks.

This might have happened because of the outdated library version. Please try one of the more recent ones here: https://artifact.soramitsu.co.jp/iroha/bindings/java/ or use a new Java library from the contributor: https://github.com/Warchant/iroha-pure-java - it is good and used in some projects based on Iroha already.

Related

Aggregate records in a stream based on time or end marker

Consider the notion of an input stream of intertwined records representing a user interaction (for example a product purchase). Imagine we receive records that indicate a user has placed a product in their shopping basket. At some time later, they perform a check-out ... or ... abandon their cart.
I thus receive a stream of records such as:
Transaction: 123, Added item A to basket
Transaction: 123, Added item B to basket
...
Transaction: 123, Checked out basket
My goal is to output from the pipeline the aggregate of the transaction. For example, given the above, I want to output:
Transaction 123, Items A, B, ... Sale completed
or if no check-out occurs within 24 hours from the last event:
Transaction 123, Items A, B, ... Sale abandoned
... and this is where I'm stuck. I feel that there is some way to think about this story from an Apache Beam pipeline perspective but I'm afraid I'm at a loss on where to begin. I'm thinking that I somehow want to window the records by both transaction and termination and only emit a batch for processing when either an end of transaction record is received or some time interval has elapsed since the last record seen.
Data based window markers have an inherent assumption on ordering of data which is not supported by Beam. In the above schenario, it is assumed that checkout event will come after all the add to the cart events.
However to solve this problem in a crude way you can use State along with Session window to express this in a crude way.
PCollection-RawEvents: Read raw events
PCollection-1: PCollection-RawEvents -> Apply 24 hour SessionWindow to all events.
PCollection-Checkout: PCollection-1 -> Push all the elements for a key in BagState. Read back the state and publish the event Transaction 123, Items A, B, ... Sale completed when you get checkout event Transaction: 123, Checked out basket.
PCollection-Abandon: PCollection-1 -> GroupByKey -> Publish Transaction 123, Items A, B, ... Sale abandoned if Transaction: 123, Checked out basket is not present.
PCollection-Unified: Flatten (PCollection-Checkout, PCollection-Abandon)

Using the result of concurrent Rails & Sidekiq jobs

Sidekiq will run 25 concurrent jobs in our scenario. We need to get a single integer as the result of each job and tally all of the results together. In this case we are querying an external API and returning counts. We want the total count from all of the API requests.
The Report object stores the final total. Postgresql is our database.
At the end of each job, we increment the report with the additional records found.
Report.find(report_id).increment(:total, api_response_total)
Is this a good approach to track the running total? Will there be Postgresql concurrency issues? Is there a better approach?
increment shouldn't lead to concurrency issues, at sql level, it updates atomically with COALESCE(total, 0) + api_response_total. Race conditions can come only if you addition manually and then saving the object.
report = Report.find(report_id)
report.total += api_response_total
report.save # NOT SAFE
Note: Even with increment! the value at Rails level can be stale, but it will be correct at database level:
# suppose initial `total` is 0
report = Report.find(report_id) # Thread 1 at time t0
report2 = Report.find(report_id) # Thread 2 at time t0
report.increment!(:total) # Thread 1 at time t1
report2.increment!(:total) # Thread 2 at time t1
report.total #=> 1 # Thread 1 at time t2
report2.total #=> 1 # Thread 2 at time t2
report.reload.total #=> 2 # Thread 1 at time t3, value was stale in object, but correct in db
Is this a good approach to track the running total? Will there be Postgresql concurrency issues? Is there a better approach?
I will prefer to do this with Sidekiq Batches. It allows you to run a batch of jobs and assign a callback to the batch, which executes once all jobs are processed. Example:
batch = Sidekiq::Batch.new
batch.description = "Batch description (this is optional)"
batch.on(:success, MyCallback, :to => user.email)
batch.jobs do
rows.each { |row| RowWorker.perform_async(row) }
end
puts "Just started Batch #{batch.bid}"
We need to get a single integer as the result of each job and tally all of the results together.
Note that Sidekiq job doesn't do anything with the returned value and the value is GC'ed and ignored. So, in above batch strategy, you will not have data of jobs in the callback. You can tailor-made that solution. For example, have a LIST in redis with key as batch id, and push the values of each complete job (in perform). In callback, simply use the list and summate it.

Rails find_in_batches with locking

I need to process large number of records in batches. And each batch should be processed in it's own transaction. Is there way to wrap each batch in transaction and lock all records in batch at the same time?
Model.scheduled_now.lock.find_in_batches do |batch|
model_ids = batch.map(&:id)
Model.update_all({status: 'delivering'}, {"id IN (?)" , model_ids})
# creates and updates other DB records
# and triggers background job
perform_delivery_actions(batch)
end
Does SELECT FOR UPDATE in this example commits transaction after each batch?
Or I need to put internal transaction block and lock records manually inside each batch (which means one more query)?
The reason I don't want to put outer transaction block is that I want to commit each batch separately, not a whole thing at once.
I ended up implementing my own find_in_batches_with_lock:
def find_in_batches_with_lock(scope, user, batch_size: 1000)
last_processed_id = 0
records = []
begin
user.transaction do
records = scope.where("id > ?", last_processed_id)
.order(:id).limit(batch_size).lock.all
next if records.empty?
yield records
last_processed_id = records.last.id
end
end while !records.empty?
end

Rails Instance Variable Conflict between Requests

I have an array of prices: #price_queue.
It is persisted in PostgreSQL as Prices.find(1).price_list and is seeded.
When a transaction is initiated, the transaction takes the next price in #price_queue, and gets sent to a payment processor for the charge.
def create
price_bucket = Prices.find(1)
price_bucket.with_lock do
#price_queue = price_bucket.price_list
#price = #price_queue.shift
price_bucket.save
end
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:card => params[:stripeToken],
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #price * 100,
)
if charge["paid"]
Pusher['price_update'].trigger('live', {message: #price_queue[0]})
end
If the transaction succeeds, it should get rid of the #price it holds.
If it fails, the price should be placed back into #price_queue.
rescue Stripe::CardError => e
flash[:error] = e.message
#price_queue.unshift(#price)
Pusher['price_update'].trigger('live', {message: #price_queue[0]})
price_bucket.price_list = #price_queue
price_bucket.save
redirect_to :back
end
I have found a major bug when testing, at milliseconds intervals, two failing transactions and then a passing one.
price_queue = [100, 101, 102, 103, ...]
User 1 gets 100 (confirmed on Stripe dashboard)
User 2 gets 101 (confirmed on Stripe dashboard)
User 3 gets 102 (confirmed on Stripe dashboard)
Expected:
Assuming no unshift has occurred yet
price_queue = [103, 104, ...]
User 1 fails, puts 100 back
price_queue = [100, 103, ...]
User 2 fails, puts 101 back
price_queue = [101, 100, 103, ...]
User 3 passes, 102 disappears
What really happens:
price_queue = [101, 102, 103, 104, ...]
As we can see, 100 is disappearing, although it should be back in the queue, 101 is back in the queue (most probably not by expected behaviour), and 102 is being put back in the queue, even though it shouldn't even traverse the rescue path.
I am using Puma on Heroku.
I have tried storing the price in session[:price], cookie[:price], assigning it to a local variable price, to no avail.
I've been reading around and figured this could be a scope problem cause by a multithreaded environment, where #price is leaking to other controller actions and being reassigned or mutated.
Any help would be greatly appreciated. (also feel free to critic my code)
This is nothing to do with instance variables leaking or anything like that - just some classic race conditions going on here. Two possible timelines:
request 1 fetches prices from the database (the array is [100,101,102])
request 2 fetches prices from the database (the array is [100,101,102] - a separate copy)
request 1 locks prices, removes a price and saves
request 2 locks prices, removes a price and saves
The important thing here is that request 2 is using an old copy of prices that doesn't include the changes made by request 1: Both of the instances will shift the same value off the array (the requests could be the different threads on the same puma worker, different workers or even different dynos - doesn't matter)
Another failure scenario would be
request 1 fetches prices, removes a price and saves. The array in the database is [101,102,103,...], the in memory array is [101,102,103, ...]
request 2 fetches prices, removes a price and saves. The array in the database is [102,103,...]
request 2's stripe transaction succeeds
request 1's stripe transaction fails, so it puts 100 back onto the array and saves. Because you haven't reloaded from the database this overwrites the changes from request 2.
To fix this properly I'd split out the logic for acquiring and replacing a price into their own methods - something like
class Prices < ActiveRecord::Base
def with_locked_row(id)
transaction do
row = lock.find(id)
result = yield row
row.save #on older versions of active record you need to tell rails about in place changes
result
end
def self.get_price(id)
with_locked_row(id) {|row| row.pricelist.shift}
end
def self.restore_price(id, value)
with_locked_row(id) {|row| row.pricelist.unshift(value}
end
end
You'd then do
Prices.get_price(1) # get a price
Prices.restore_price(1, some_value) #put a price back if the charging failed
The key differences between this and your original code are that:
I acquire a locked row and update it, rather than acquiring a row and then locking it. This eliminates the window in the first scenario I outlined
I don't keep using the same active record object after I've released the lock - as soon as the lock has been released someone else might be changing it behind your back.
You could also do this via optimistic locking (i.e without explicit locks). The only thing that would change code-wise would be
def with_locked_row(id)
begin
row = lock.find(id)
result = yield row
row.save #on older versions of active record you need to tell rails about in place changes
result
rescue ActiveRecord::StaleObjectError
retry
end
end
You would need to add a non null integer column with default value 0 called lock_version for this to work.
Which performs better depends on how much concurrency you experience, what other accesses there are to this table and so on. Personally I would default to optimistic locking unless I had a compelling reason to do otherwise.

Using SimpleDB NextToken when records in query are updated

I have a case where we are doing a select on a domain like:
select * from mydomain where some_val = 'foo' and some_date < '2012-03-01T00:00+01:00'
When iterating the results of this query - we are doing some work and then updating the row and setting the field some_date to the current date/time. Marking that it's processed.
The question I have is will the nexttoken request break when it returns to simpledb to get the next set of records? When it returns to get the next batch - all of the ones in the first batch will now have some_date with a value that no longer is within the original query range.
I don't know how the next-token is implemented to know whether its just a pointer to the next item or whether it somehow is an offset that might "skip" a whole batch of records.
So if we retrieved 3 records at a time and I had this in my domain:
record 1, '2012-01-12T19:20+01:00'
record 2, '2012-02-14T19:20+01:00'
record 3, '2012-01-22T19:20+01:00'
record 4, '2012-01-21T19:20+01:00'
record 5, '2012-02-22T19:20+01:00'
record 6, '2012-01-20T19:20+01:00'
record 7, '2012-01-18T19:20+01:00'
record 8, '2012-01-17T19:20+01:00'
record 9, '2012-02-12T19:20+01:00'
My first execution I would get: record 1, 2, 3
If i set their some_date field to: '2012-03-12T19:20+01:00' before returning for the next-token batch - would the next-token request then return 4,5,6? Or would it return 7,8,9 (because the token was set to start at the 4th record and now 1,2,3 are no longer in the result set).
If it is important - we are using the boto library (python).
would the next-token request then return 4,5,6? Or would it return
7,8,9 [...]?
Good question, this can indeed be a bit confusing - still anything but the former (i.e. 4,5,6) wouldn't make sense for practical usage and Amazon SimpleDB works like so accordingly, see Select:
Operations that run longer than 5 seconds return a time-out error
response or a partial or empty result set. Partial and empty result
sets contain a NextToken value, which allows you to continue the
operation from where it left off [emphasis mine]
Please take note of the additional note in section Request Parameters though, which might be a bit surprising eventually:
Note
The response to a Select operation with ConsistentRead set to
true returns a consistent read. However, for any following Select
operation requests that include a NextToken value, Amazon SimpleDB
ignores the ConsistentRead field, and the subsequent results are
eventually consistent. [emphasis mine]

Resources