Are transactions in a batch serialized? - nearprotocol

if I send a transaction with 2 contract fn calls, does the 2nd gets executed if the 1st fails?
sample code:
const actions = [
TX.functionCall("select_staking_pool", { staking_pool_account_id: stakingPool }, this.BASE_GAS.muln(3), new BN(0)),
TX.functionCall("deposit_and_stake", { amount: near.ntoy(amountNear) }, this.BASE_GAS.muln(5), new BN(0))
]
return near.broadcast_tx_commit_actions(actions, sender, lockupContract, privateKey)
I did execute this batch, but the result gives me no clear answer: https://explorer.testnet.near.org/transactions/DcchgGdzAVEvNqRReHkjsmrTr5PoaMoibs3fyKoKBYSe
The 1st fn call code uses cross-contract calls and a callback code to check if the contract is whitelisted, but I can't see the callback's log code in the receipt logs. I assume the 1st call fails because the second fails with the error: "staking pool is not selected"
Here's the full result:
{
"status": {
"Failure": {
"ActionError": {
"index": 1,
"kind": {
"FunctionCallError": {
"HostError": {
"GuestPanic": {
"panic_msg": "panicked at 'Staking pool is not selected', src/internal.rs:90:9"
}
}
}
}
}
}
},
"transaction": {
"signer_id": "lucio.testnet",
"public_key": "ed25519:Cvqie7SJ6xmLNA5KoTAYoUAkhD25KaJLG6N9oSmzT9FK",
"nonce": 33,
"receiver_id": "274e981786efcabbe87794f20348c1b2af6e7963.lockupy.testnet",
"actions": [
{
"FunctionCall": {
"method_name": "select_staking_pool",
"args": "eyJzdGFraW5nX3Bvb2xfYWNjb3VudF9pZCI6Im5vcnRoZXJubGlnaHRzLnN0YWtpbmdwb29sIn0=",
"gas": 75000000000000,
"deposit": "0"
}
},
{
"FunctionCall": {
"method_name": "deposit_and_stake",
"args": "eyJhbW91bnQiOiIxMDk0OTkwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIn0=",
"gas": 125000000000000,
"deposit": "0"
}
}
],
"signature": "ed25519:gzCsrcobVtjuD6FE4qDhgo9zdk2feBp6dfa66NZYLPTnwypF7g8mDM7yubcnkVcF1sPzEFeEfJtQ4hwwnhrxTa6",
"hash": "EjiQBjzF6Ea74wSHkjmZMkhTGwgYxbUdeVKUvzaA8X7k"
},
"transaction_outcome": {
"proof": [],
"block_hash": "3xEuw43E1W4FP2q1Un6XLsDSbhRc7c7FMtGWWL6i3KJj",
"id": "EjiQBjzF6Ea74wSHkjmZMkhTGwgYxbUdeVKUvzaA8X7k",
"outcome": {
"logs": [],
"receipt_ids": [
"75pJCVuheYCjX82RspQzoKm5v7NSG1QNUaPK7DRzZYNt"
],
"gas_burnt": 4748079879222,
"tokens_burnt": "474807987922200000000",
"executor_id": "lucio.testnet",
"status": {
"SuccessReceiptId": "75pJCVuheYCjX82RspQzoKm5v7NSG1QNUaPK7DRzZYNt"
}
}
},
"receipts_outcome": [
{
"proof": [
{
"hash": "55YXLhqDc63f8n4MdZNwi6TdmtFkaYp18wKwm7qFmDo5",
"direction": "Left"
}
],
"block_hash": "DB3p49tiSBfRLv5diDUStajtDiMNs2KroKfRcr2cQDnV",
"id": "75pJCVuheYCjX82RspQzoKm5v7NSG1QNUaPK7DRzZYNt",
"outcome": {
"logs": [
"Selecting staking pool #northernlights.stakingpool. Going to check whitelist first."
],
"receipt_ids": [
"HXStMQuf5aWKVpWDM1Hf4EdA3S4FLTGjmYaF2WAYRcUz"
],
"gas_burnt": 20291176638173,
"tokens_burnt": "2029117663817300000000",
"executor_id": "274e981786efcabbe87794f20348c1b2af6e7963.lockupy.testnet",
"status": {
"Failure": {
"ActionError": {
"index": 1,
"kind": {
"FunctionCallError": {
"HostError": {
"GuestPanic": {
"panic_msg": "panicked at 'Staking pool is not selected', src/internal.rs:90:9"
}
}
}
}
}
}
}
}
},
{
"proof": [],
"block_hash": "2kua8s7vjix2MiMHZ7Rzbrhyv8UbGFEpvWeT67H2qCYM",
"id": "HXStMQuf5aWKVpWDM1Hf4EdA3S4FLTGjmYaF2WAYRcUz",
"outcome": {
"logs": [],
"receipt_ids": [],
"gas_burnt": 0,
"tokens_burnt": "0",
"executor_id": "lucio.testnet",
"status": {
"SuccessValue": ""
}
}
}
]
}
Edit: PS. It looks like the 1st function call was failing silently (regarding Tx result). I tested the same calls as 2 separate transactions and the 1st one (select_staking_pool) succeeded.

All later actions after the first failed action are not executed. And their execution fees are refunded. All the changes that were successfully executed before, will be reverted and all the promises will not be scheduled and executed either.
Your case is more complicated, because the first action succeeds by returning a promise. The resulting promise later will fails in the callback, but the second action fails immediately, because the staking pool is not selected yet due to async execution. So the first promise doesn't get scheduled.
EDIT 1.
Once a transaction or a receipt succeeds (finishes all actions) it doesn't rollback anything. So if any future promises fail they are going to be independently executing from each other. Also only the last action in a batch of actions returns the result for the entire receipt.

Related

Unable to start AWSFIS-Run-CPU-Stress

While running AWSFIS-Run-CPU-Stress i am getting below error:
Unable to start action, due to a platform mismatch between the specified document and the targeted instances. I am trying this in Windows EC2 instance
My Experiment script look like this(removed confidential server info):
{
"description": "Test CPU stress predefined SSM document",
"targets": {
"testInstance": {
"resourceType": "aws:ec2:instance",
"resourceArns": [
"arn:aws:ec2:region:123456789012:instance/instance_id"
],
"selectionMode": "ALL"
}
},
"actions": {
"runCpuStress": {
"actionId": "aws:ssm:send-command",
"parameters": {
"documentArn": "arn:aws:ssm:region::document/AWSFIS-Run-CPU-Stress",
"documentParameters": "{\"DurationSeconds\":\"120\"}",
"duration": "PT5M"
},
"targets": {
"Instances": "testInstance"
}
}
},
"stopConditions": [
{
"source": "aws:cloudwatch:alarm",
"value": "arn:aws:cloudwatch:region:123456789012:alarm:awsec2-instance_id-GreaterThanOrEqualToThreshold-CPUUtilization"
}
],
"roleArn": "arn:aws:iam::123456789012:role/AllowFISSSMActions",
"tags": {}
}

NEAR transaction without receipt but with receipt_outcome

When querying archival node for transactions with EXPERIMENTAL_tx_status method, some transactions have no receipts while having receipts_outcome. How is that possible, and how is that transaction different from others?
If I understand correctly, receipts_outcome are the results of applying receipts. According to explorer, this transaction has Convert Transaction To Receipt part, so there should be some receipts generated.
According to documentation
A Receipt is the only actionable object in the system. When we talk about "processing a transaction" on the NEAR platform, this eventually means "applying receipts" at some point.
A good mental model is to think of a Receipt as a paid message to be executed at the destination (receiver). And a Transaction is an externally issued request to create the Receipt (there is a 1 to 1 relationship).
My query
{
"jsonrpc": "2.0",
"id": "2",
"method": "EXPERIMENTAL_tx_status",
"params": ["7beNxrbHxMRspJWT9NeEVwx719kVcmY9tRdPG9SYro26", "bumbleee99.near"]
}
Response
{
"jsonrpc": "2.0",
"result": {
"status": {
"SuccessValue": ""
},
"transaction": {
"signer_id": "bumbleee99.near",
"public_key": "ed25519:DFM5GRGbpNkk4XkhcFnRUFeKG8a3nzTH8NwZp754pC48",
"nonce": 59080995000003,
"receiver_id": "bumbleee99.near",
"actions": [
{
"AddKey": {
"public_key": "ed25519:CUoNs153GHrPZ9F8HpvhzFr1mwuUFUdGQsRNE2CTNjVH",
"access_key": {
"nonce": 0,
"permission": "FullAccess"
}
}
}
],
"signature": "ed25519:15v34qoyCHSvSL5uLcaPqD9vXvjcPrCaZVStCMms8e58C62z2UHiazwUXzHajPEgdHpwn7s4J9dd5UPmtvzbYgM",
"hash": "7beNxrbHxMRspJWT9NeEVwx719kVcmY9tRdPG9SYro26"
},
"transaction_outcome": {
"proof": [
{
"hash": "ECKDm5FVhzit7Wqs9sEyBB9NtuTrVRZmWwcxkkg2yUh4",
"direction": "Right"
},
{
"hash": "E4VXdwsNj3fZCbP6y9YH3M5oZHPDcdArqU9kbZJa95Qp",
"direction": "Right"
}
],
"block_hash": "ASY6HgDUQUXUa99L7dPEfghKEnEk5SNkwQrx24u3Fobz",
"id": "7beNxrbHxMRspJWT9NeEVwx719kVcmY9tRdPG9SYro26",
"outcome": {
"logs": [],
"receipt_ids": [
"JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"
],
"gas_burnt": 209824625000,
"tokens_burnt": "20982462500000000000",
"executor_id": "bumbleee99.near",
"status": {
"SuccessReceiptId": "JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"
},
"metadata": {
"version": 1,
"gas_profile": null
}
}
},
"receipts_outcome": [
{
"proof": [
{
"hash": "8RwCWE9HgqenPKv8JW9eg2iSLMaQW82wvebYSfjPbdTY",
"direction": "Left"
},
{
"hash": "E4VXdwsNj3fZCbP6y9YH3M5oZHPDcdArqU9kbZJa95Qp",
"direction": "Right"
}
],
"block_hash": "ASY6HgDUQUXUa99L7dPEfghKEnEk5SNkwQrx24u3Fobz",
"id": "JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ",
"outcome": {
"logs": [],
"receipt_ids": [],
"gas_burnt": 209824625000,
"tokens_burnt": "20982462500000000000",
"executor_id": "bumbleee99.near",
"status": {
"SuccessValue": ""
},
"metadata": {
"version": 1,
"gas_profile": []
}
}
}
],
"receipts": []
},
"id": "2"
}
You could see that both transaction_outcome.outcome.receipt_ids and transaction_outcome.outcome.status are pointing to a receipt with ID JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ. I've tried querying node about this receipt with EXPERIMENTAL_receipt method like this
{
"jsonrpc": "2.0",
"id": "2",
"method": "EXPERIMENTAL_receipt",
"params": {"receipt_id": "JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"}
}
yet the node returns error indicating, that there is no receipt with given ID
{
"jsonrpc": "2.0",
"error": {
"name": "HANDLER_ERROR",
"cause": {
"name": "UNKNOWN_RECEIPT",
"info": {
"receipt_id": "JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"
}
},
"code": -32000,
"message": "Server error",
"data": {
"name": "UNKNOWN_RECEIPT",
"info": {
"receipt_id": "JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"
}
}
},
"id": "2"
}
TL;DR the receipt is a local receipt
The transaction from your example is a simple AddKey action where the sender is the receiver (remember this, it's important)
"Execute" transaction (means to convert the transaction into a Receipt)
Apply the Receipts
As the result of the conversion of the transaction into a receipt is your transaction_outcome
"outcome": {
"receipt_ids": [
"JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"
],
"status": {
"SuccessReceiptId": "JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ"
},
This receipt is about to be applied and the predecessor_id and the receiver_id are equal. In nearcore such receipts are called local receipts (sir - sender-is-receiver) and those receipts are not stored in the nearcore database.
We emulate them on NEAR Indexer Framework side (that's why you can see Receipt JDnBrxh6L9KFgVUEg6U8d39rEUEmbvLQ5tZQUmJTMyFJ on the transaction details page on NEAR Explorer)
And because nearcore doesn't store such receipts in the database you got UNKNOWN_RECEIPT from the RPC.

Step Functions ignoring Parameters, executing it with default input

I don't know if this is a bug of my own or Amazon's as I'm unable to properly understand what's going on.
I have the following Step Function (It's currently a work in progress), which takes care of validating an input and then sending it to an SQS lambda (CreateInAuth0 Step).
My problem is that apparently the SQS function is executing with the default parameters, fails, retries and then uses the ones specified in the Step Function. (Or at least that's what I'm gathering from the logs).
I want to know why it is ignoring the Parameters in the first go. Here's all the information I can gather.
There seems to be a difference between TaskStateEntered and TaskScheduled (which I believe it's ok).
{
"Comment": "Add the students to the platform and optionally adds them to their respective grades",
"StartAt": "AddStudents",
"States": {
"AddStudents": {
"Comment": "Validates that the students are OK",
"Type": "Task",
"Resource": "#AddStudents",
"Next": "Parallel"
},
"Parallel": {
"Type": "Parallel",
"Next": "FinishExecution",
"Branches": [
{
"StartAt": "CreateInAuth0",
"States": {
"CreateInAuth0": {
"Type": "Task",
"Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken",
"Parameters": {
"QueueUrl": "#SQS_StudentsRegistrationSQSFifo",
"MessageBody": {
"execId.$": "$.result.execId",
"tenantType.$": "$.result.tenantType",
"tenantId.$": "$.result.tenantId",
"studentsToCreate.$": "$.result.newStudents.success",
"TaskToken.$": "$$.Task.Token",
"studentsSucceeded": []
}
},
"End": true
}
}
}
]
},
"FinishExecution": {
"Comment": "This signals the ending in DynamoDB that the transaction finished",
"Type": "Task",
"End": true,
"Resource": "arn:aws:states:::dynamodb:putItem",
"ResultPath": "$.dynamoDB",
"Parameters": {
"TableName": "#SchonDB",
"Item": {
"pk": {
"S.$": "$.arguments.tenantId:exec:$.id"
},
"sk": {
"S": "result"
},
"status": {
"S": "FINISHED"
},
"type": {
"S": "#EXEC_TYPE"
}
}
},
"Retry": [
{
"ErrorEquals": [
" States.Timeout"
],
"IntervalSeconds": 1,
"MaxAttempts": 5,
"BackoffRate": 2.0
}
],
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "FinishExecutionIfFinishErrored"
}
]
},
"FinishExecutionIfFinishErrored": {
"Type": "Pass",
"End": true
}
}
}
Here's the visual:
Here's the execution event history:
Note: I have a try/catch statement inside the SQS function that wraps the entire SQS' execution.

Get the trigger that invoked the lambda when it is invoked

I have an AWS lambda with multiple triggers. When the lambda is invoked, I'd like to be able to determine which trigger invoked the lambda within the lambda code itself. Is this information available somehow? I tried looking at the event object and the context object, but I did not see that information available. Is there some api I can call to get the trigger or another way to get that information reliably?
Answering late but may help someone else looking for solution-
As #Leon mentioned, eventSource would work. For example, below are two different payload for s3 and sqs-
{
"Records": [
{
"eventVersion": "2.1",
"eventSource": "aws:s3",
"awsRegion": "us-east-2",
"eventTime": "2019-09-03T19:37:27.192Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "AWS:AIDAINPONIXQXHT3IKHL2"
},
"requestParameters": {
"sourceIPAddress": "205.255.255.255"
},
"responseElements": {
"x-amz-request-id": "D82B88E5F771F645",
"x-amz-id-2": "vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo="
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "828aa6fc-f7b5-4305-8584-487c791949c1",
"bucket": {
"name": "DOC-EXAMPLE-BUCKET",
"ownerIdentity": {
"principalId": "A3I5XTEXAMAI3E"
},
"arn": "arn:aws:s3:::lambda-artifacts-deafc19498e3f2df"
},
"object": {
"key": "b21b84d653bb07b05b1e6b33684dc11b",
"size": 1305107,
"eTag": "b21b84d653bb07b05b1e6b33684dc11b",
"sequencer": "0C0F6F405D6ED209E1"
}
}
}
]
}
SQS-
{
"Records": [
{
"messageId": "11d6ee51-4cc7-4302-9e22-7cd8afdaadf5",
"receiptHandle": "AQEBBX8nesZEXmkhsmZeyIE8iQAMig7qw...",
"body": "Test message.",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1573251510774",
"SequenceNumber": "18849496460467696128",
"MessageGroupId": "1",
"SenderId": "AIDAIO23YVJENQZJOL4VO",
"MessageDeduplicationId": "1",
"ApproximateFirstReceiveTimestamp": "1573251510774"
},
"messageAttributes": {},
"md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:fifo.fifo",
"awsRegion": "us-east-2"
}
]
}
Now you can use -
source = event['Records'][0]['eventSource']
This should give the resource name, in case of s3 you would get aws:s3, and for sqs- aws:sqs.

Getting started with Step Functions and I can't get Choice to work correctly

I'm doctoring up my first step function, and as a newb into this I am struggling to make this work right. The documentation on AWS is helpful but lacks examples of what I am trying understand. I found a couple similar issues on the site here, but they didn't really answer my question either.
I have a test Step Function that works really simply. I have a small Lambda function that kicks out a single line JSON with a "Count" from a request in a DynamoDB:
def lambda_handler(event, context):
"""lambda_handler
Keyword arguments:
event -- dict -- A dict of parameters to be validated.
context --
Return:
json object with the hubID from DynamoDB of the new hub.
Exceptions:
None
"""
# Prep the Boto3 resources needed
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('TransitHubs')
# By default we assume there are no new hubs
newhub = { 'Count' : 0 }
# Query the DynamoDB to see if the name exists or not:
response = table.query(
IndexName='Status-index',
KeyConditionExpression=Key('Status').eq("NEW"),
Limit=1
)
if response['Count']:
newhub['Count'] = response['Count']
return json.dumps(newhub)
A normal output would be:
{ "Count": 1 }
And then I create this Step Function:
{
"StartAt": "Task",
"States": {
"Task": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-west-2:OMGSUPERSECRET:function:LaunchNode-get_new_hubs",
"TimeoutSeconds": 60,
"Next": "Choice"
},
"Choice": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.Count",
"NumericEquals": 0,
"Next": "Failed"
},
{
"Variable": "$.Count",
"NumericEquals": 1,
"Next": "Succeed"
}
]
},
"Succeed": {
"Type": "Succeed"
},
"Failed": {
"Type": "Fail"
}
}
}
So I kick off the State Function and I get this output:
TaskStateExited
{
"name": "Task",
"output": {
"Count": 1
}
}
ChoiceStateEntered
{
"name": "Choice",
"input": {
"Count": 1
}
}
ExecutionFailed
{
"error": "States.Runtime",
"cause": "An error occurred while executing the state 'Choice' (entered at the event id #7). Invalid path '$.Count': The choice state's condition path references an invalid value."
}
So my question: I don't get why this is failing with that error message. Shouldn't Choice just pick up that value from the JSON? Isn't the default "$" input the "input" path?
I have figured out what the issue is, and here it is:
In my Python code, I was attempting to json.dumps(newhub) for the response thinking that what I needed was a string output representing the json formatted response. But it appears that is incorrect. When I alter the code to be simply "return newhub" and return the DICT, the step-functions process accepts that correctly. I'm assuming it parses the DICT to JSON for me? But the output difference is clearly obvious:
old Task output from above returning json.dumps(newhub):
{
"name": "Task",
"output": {
"Count": 1
}
}
new Task output from above returning newhub:
{
"Count": 1
}
And the Choice now correctly matches the Count variable in my output.
In case this is helpful for someone else. I also experienced the kind of error you did ( you had the below... just copy-pasting yours... )
{
"error": "States.Runtime",
"cause": "An error occurred while executing the state 'Choice' (entered at the event id #7). Invalid path '$.Count': The choice state's condition path references an invalid value."
}
But my problem turned out when I was missing the "Count" key all together.
But I did not want verbose payloads.
But per reading these docs I discovered I can also do...
"Choice": {
"Type": "Choice",
"Choices": [
{
"And": [
{
"Variable": "$.Count",
"IsPresent": true
},
{
"Variable": "$.Count",
"NumericEquals": 0,
}
],
"Next": "Failed"
},
{
"And": [
{
"Variable": "$.Count",
"IsPresent": true
},
{
"Variable": "$.Count",
"NumericEquals": 1,
}
],
"Next": "Succeed"
}
]
},
even I was facing the same issue. Give the ResultPath as InputPath and give the choice value as .value name
{
"Comment": "Step function to execute lengthy synchronous requests",
"StartAt": "StartProcessing",
"States": {
"StartProcessing": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:703569030910:function:shravanthDemo-shravanthGetItems-GHF7ZA1p6auQ",
"InputPath": "$.lambda",
"ResultPath": "$.lambda",
"Next": "VerifyProcessor"
},
"VerifyProcessor": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.lambda.cursor",
"IsNull": false,
"Next": "StartProcessing"
},
{
"Variable": "$.lambda.cursor",
"IsNull": true,
"Next": "EndOfUpdate"
}
]
},
"EndOfUpdate": {
"Type": "Pass",
"Result": "ProcessingComplete",
"End": true
}
}
}

Resources