Skip to content

Commit

Permalink
Merge pull request #2326 from planetarium/feature/transaction-results…
Browse files Browse the repository at this point in the history
…-query

Introduce TransactionResults query
  • Loading branch information
ipdae authored Nov 27, 2023
2 parents 7e47db5 + df5c6a7 commit 8aa2d98
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,41 @@ public async Task TransactionResultIsSuccess()
Assert.Equal("SUCCESS", txStatus);
}

[Fact]
public async Task TransactionResults()
{
var privateKey = new PrivateKey();
// Because `AddActivatedAccount` doesn't need any prerequisites.
var action = new AddActivatedAccount(default);
Transaction tx = _blockChain.MakeTransaction(privateKey, new ActionBase[] { action });
var action2 = new DailyReward
{
avatarAddress = default
};
Transaction tx2 = _blockChain.MakeTransaction(new PrivateKey(), new ActionBase[] { action2 });
Block block = _blockChain.ProposeBlock(_proposer);
_blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, _proposer));
var queryFormat = @"query {{
transactionResults(txIds: [""{0}"", ""{1}""]) {{
blockHash
txStatus
}}
}}";
var result = await ExecuteAsync(string.Format(
queryFormat,
tx.Id.ToString(),
tx2.Id.ToString()
));
Assert.NotNull(result.Data);
var transactionResults =
(object[])((Dictionary<string, object>)((ExecutionNode)result.Data!).ToValue()!)["transactionResults"];
Assert.Equal(2, transactionResults.Length);
var txStatus = (string)((Dictionary<string, object>)transactionResults[0])["txStatus"];
Assert.Equal("SUCCESS", txStatus);
txStatus = (string)((Dictionary<string, object>)transactionResults[1])["txStatus"];
Assert.Equal("FAILURE", txStatus);
}

[Fact]
public async Task NcTransactionsOnTip()
{
Expand Down
88 changes: 55 additions & 33 deletions NineChronicles.Headless/GraphTypes/TransactionHeadlessQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,42 +192,25 @@ public TransactionHeadlessQuery(StandaloneContext standaloneContext)
),
resolve: context =>
{
if (!(standaloneContext.BlockChain is BlockChain blockChain))
{
throw new ExecutionError(
$"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!");
}
if (!(standaloneContext.Store is IStore store))
{
throw new ExecutionError(
$"{nameof(StandaloneContext)}.{nameof(StandaloneContext.Store)} was not set yet!");
}
TxId txId = context.GetArgument<TxId>("txId");
if (!(store.GetFirstTxIdBlockHashIndex(txId) is { } txExecutedBlockHash))
{
return blockChain.GetStagedTransactionIds().Contains(txId)
? new TxResult(TxStatus.STAGING, null, null, null, null, null)
: new TxResult(TxStatus.INVALID, null, null, null, null, null);
}
var txId = context.GetArgument<TxId>("txId");
return TxResult(standaloneContext, txId);
});

try
{
TxExecution execution = blockChain.GetTxExecution(txExecutedBlockHash, txId);
Block txExecutedBlock = blockChain[txExecutedBlockHash];
return new TxResult(
execution.Fail ? TxStatus.FAILURE : TxStatus.SUCCESS,
txExecutedBlock.Index,
txExecutedBlock.Hash.ToString(),
execution.InputState,
execution.OutputState,
execution.ExceptionNames);
}
catch (Exception)
Field<NonNullGraphType<ListGraphType<TxResultType>>>(
name: "transactionResults",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<ListGraphType<NonNullGraphType<TxIdType>>>>
{
return new TxResult(TxStatus.INVALID, null, null, null, null, null);
Name = "txIds",
Description = "transaction ids."
}
),
resolve: context =>
{
return context.GetArgument<List<TxId>>("txIds")
.AsParallel()
.AsOrdered()
.Select(txId => TxResult(standaloneContext, txId));
}
);

Expand Down Expand Up @@ -312,6 +295,45 @@ public TransactionHeadlessQuery(StandaloneContext standaloneContext)
);
}

private static object? TxResult(StandaloneContext standaloneContext, TxId txId)
{
if (!(standaloneContext.BlockChain is BlockChain blockChain))
{
throw new ExecutionError(
$"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!");
}

if (!(standaloneContext.Store is IStore store))
{
throw new ExecutionError(
$"{nameof(StandaloneContext)}.{nameof(StandaloneContext.Store)} was not set yet!");
}

if (!(store.GetFirstTxIdBlockHashIndex(txId) is { } txExecutedBlockHash))
{
return blockChain.GetStagedTransactionIds().Contains(txId)
? new TxResult(TxStatus.STAGING, null, null, null, null, null)
: new TxResult(TxStatus.INVALID, null, null, null, null, null);
}

try
{
TxExecution execution = blockChain.GetTxExecution(txExecutedBlockHash, txId);
Block txExecutedBlock = blockChain[txExecutedBlockHash];
return new TxResult(
execution.Fail ? TxStatus.FAILURE : TxStatus.SUCCESS,
txExecutedBlock.Index,
txExecutedBlock.Hash.ToString(),
execution.InputState,
execution.OutputState,
execution.ExceptionNames);
}
catch (Exception)
{
return new TxResult(TxStatus.INVALID, null, null, null, null, null);
}
}

private IEnumerable<Block> ListBlocks(BlockChain chain, long from, long limit)
{
if (chain.Tip.Index < from)
Expand Down

0 comments on commit 8aa2d98

Please sign in to comment.