mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-22 17:45:10 +00:00
Add getCreator() to parsed transaction in off_chain_data sample (#806)
Example of how the client identity that submitted a transaction can be obtained. Signed-off-by: Mark S. Lewis <mark_lewis@uk.ibm.com>
This commit is contained in:
parent
cb4355125f
commit
51397fe78a
6 changed files with 120 additions and 103 deletions
|
|
@ -10,6 +10,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import org.hyperledger.fabric.protos.common.ChannelHeader;
|
import org.hyperledger.fabric.protos.common.ChannelHeader;
|
||||||
import org.hyperledger.fabric.protos.common.HeaderType;
|
import org.hyperledger.fabric.protos.common.HeaderType;
|
||||||
import org.hyperledger.fabric.protos.common.Payload;
|
import org.hyperledger.fabric.protos.common.Payload;
|
||||||
|
import org.hyperledger.fabric.protos.common.SignatureHeader;
|
||||||
import org.hyperledger.fabric.protos.peer.TxValidationCode;
|
import org.hyperledger.fabric.protos.peer.TxValidationCode;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
@ -18,6 +19,7 @@ class ParsedPayload {
|
||||||
private final Payload payload;
|
private final Payload payload;
|
||||||
private final TxValidationCode statusCode;
|
private final TxValidationCode statusCode;
|
||||||
private final AtomicReference<ChannelHeader> cachedChannelHeader = new AtomicReference<>();
|
private final AtomicReference<ChannelHeader> cachedChannelHeader = new AtomicReference<>();
|
||||||
|
private final AtomicReference<SignatureHeader> cachedSignatureHeader = new AtomicReference<>();
|
||||||
|
|
||||||
ParsedPayload(final Payload payload, final TxValidationCode statusCode) {
|
ParsedPayload(final Payload payload, final TxValidationCode statusCode) {
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
|
|
@ -28,6 +30,10 @@ class ParsedPayload {
|
||||||
return Utils.getCachedProto(cachedChannelHeader, () -> ChannelHeader.parseFrom(payload.getHeader().getChannelHeader()));
|
return Utils.getCachedProto(cachedChannelHeader, () -> ChannelHeader.parseFrom(payload.getHeader().getChannelHeader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SignatureHeader getSignatureHeader() throws InvalidProtocolBufferException {
|
||||||
|
return Utils.getCachedProto(cachedSignatureHeader, () -> SignatureHeader.parseFrom(payload.getHeader().getSignatureHeader()));
|
||||||
|
}
|
||||||
|
|
||||||
public TxValidationCode getValidationCode() {
|
public TxValidationCode getValidationCode() {
|
||||||
return statusCode;
|
return statusCode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ final class ParsedTransaction implements Transaction {
|
||||||
return payload.getChannelHeader();
|
return payload.getChannelHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getCreator() throws InvalidProtocolBufferException {
|
||||||
|
return payload.getSignatureHeader().getCreator().toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TxValidationCode getValidationCode() {
|
public TxValidationCode getValidationCode() {
|
||||||
return payload.getValidationCode();
|
return payload.getValidationCode();
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import java.util.List;
|
||||||
|
|
||||||
public interface Transaction {
|
public interface Transaction {
|
||||||
ChannelHeader getChannelHeader() throws InvalidProtocolBufferException;
|
ChannelHeader getChannelHeader() throws InvalidProtocolBufferException;
|
||||||
|
byte[] getCreator() throws InvalidProtocolBufferException;
|
||||||
TxValidationCode getValidationCode();
|
TxValidationCode getValidationCode();
|
||||||
boolean isValid();
|
boolean isValid();
|
||||||
List<NamespaceReadWriteSet> getNamespaceReadWriteSets() throws InvalidProtocolBufferException;
|
List<NamespaceReadWriteSet> getNamespaceReadWriteSets() throws InvalidProtocolBufferException;
|
||||||
|
|
|
||||||
99
off_chain_data/application-typescript/.eslintrc.js
Normal file
99
off_chain_data/application-typescript/.eslintrc.js
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
es2020: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
],
|
||||||
|
root: true,
|
||||||
|
ignorePatterns: [
|
||||||
|
'dist/',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'arrow-spacing': ['error'],
|
||||||
|
'comma-style': ['error'],
|
||||||
|
complexity: ['error', 10],
|
||||||
|
'eol-last': ['error'],
|
||||||
|
'generator-star-spacing': ['error', 'after'],
|
||||||
|
'key-spacing': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
beforeColon: false,
|
||||||
|
afterColon: true,
|
||||||
|
mode: 'minimum',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'keyword-spacing': ['error'],
|
||||||
|
'no-multiple-empty-lines': ['error'],
|
||||||
|
'no-trailing-spaces': ['error'],
|
||||||
|
'no-whitespace-before-property': ['error'],
|
||||||
|
'object-curly-newline': ['error'],
|
||||||
|
'padded-blocks': ['error', 'never'],
|
||||||
|
'rest-spread-spacing': ['error'],
|
||||||
|
'semi-style': ['error'],
|
||||||
|
'space-before-blocks': ['error'],
|
||||||
|
'space-in-parens': ['error'],
|
||||||
|
'space-unary-ops': ['error'],
|
||||||
|
'spaced-comment': ['error'],
|
||||||
|
'template-curly-spacing': ['error'],
|
||||||
|
'yield-star-spacing': ['error', 'after'],
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'**/*.ts',
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
sourceType: 'module',
|
||||||
|
ecmaFeatures: {
|
||||||
|
impliedStrict: true,
|
||||||
|
},
|
||||||
|
project: './tsconfig.json',
|
||||||
|
tsconfigRootDir: process.env.TSCONFIG_ROOT_DIR || __dirname,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'@typescript-eslint',
|
||||||
|
],
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/comma-spacing': ['error'],
|
||||||
|
'@typescript-eslint/explicit-function-return-type': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowExpressions: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/func-call-spacing': ['error'],
|
||||||
|
'@typescript-eslint/member-delimiter-style': ['error'],
|
||||||
|
'@typescript-eslint/indent': [
|
||||||
|
'error',
|
||||||
|
4,
|
||||||
|
{
|
||||||
|
SwitchCase: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/prefer-nullish-coalescing': ['error'],
|
||||||
|
'@typescript-eslint/prefer-optional-chain': ['error'],
|
||||||
|
'@typescript-eslint/prefer-reduce-type-parameter': ['error'],
|
||||||
|
'@typescript-eslint/prefer-return-this-type': ['error'],
|
||||||
|
'@typescript-eslint/quotes': ['error', 'single'],
|
||||||
|
'@typescript-eslint/type-annotation-spacing': ['error'],
|
||||||
|
'@typescript-eslint/semi': ['error'],
|
||||||
|
'@typescript-eslint/space-before-function-paren': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
anonymous: 'never',
|
||||||
|
named: 'never',
|
||||||
|
asyncArrow: 'always',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
env:
|
|
||||||
node: true
|
|
||||||
es2020: true
|
|
||||||
extends:
|
|
||||||
- eslint:recommended
|
|
||||||
rules:
|
|
||||||
arrow-spacing:
|
|
||||||
- error
|
|
||||||
comma-style:
|
|
||||||
- error
|
|
||||||
complexity:
|
|
||||||
- error
|
|
||||||
- 10
|
|
||||||
eol-last:
|
|
||||||
- error
|
|
||||||
generator-star-spacing:
|
|
||||||
- error
|
|
||||||
- after
|
|
||||||
key-spacing:
|
|
||||||
- error
|
|
||||||
- beforeColon: false
|
|
||||||
afterColon: true
|
|
||||||
mode: minimum
|
|
||||||
keyword-spacing:
|
|
||||||
- error
|
|
||||||
no-multiple-empty-lines:
|
|
||||||
- error
|
|
||||||
no-trailing-spaces:
|
|
||||||
- error
|
|
||||||
no-whitespace-before-property:
|
|
||||||
- error
|
|
||||||
object-curly-newline:
|
|
||||||
- error
|
|
||||||
padded-blocks:
|
|
||||||
- error
|
|
||||||
- never
|
|
||||||
rest-spread-spacing:
|
|
||||||
- error
|
|
||||||
semi-style:
|
|
||||||
- error
|
|
||||||
space-before-blocks:
|
|
||||||
- error
|
|
||||||
space-in-parens:
|
|
||||||
- error
|
|
||||||
space-unary-ops:
|
|
||||||
- error
|
|
||||||
spaced-comment:
|
|
||||||
- error
|
|
||||||
template-curly-spacing:
|
|
||||||
- error
|
|
||||||
yield-star-spacing:
|
|
||||||
- error
|
|
||||||
- after
|
|
||||||
overrides:
|
|
||||||
- files:
|
|
||||||
- "**/*.ts"
|
|
||||||
parser: "@typescript-eslint/parser"
|
|
||||||
parserOptions:
|
|
||||||
sourceType: module
|
|
||||||
ecmaFeatures:
|
|
||||||
impliedStrict: true
|
|
||||||
project: "tsconfig.json"
|
|
||||||
tsconfigRootDir: "."
|
|
||||||
plugins:
|
|
||||||
- "@typescript-eslint"
|
|
||||||
extends:
|
|
||||||
- eslint:recommended
|
|
||||||
- plugin:@typescript-eslint/recommended
|
|
||||||
- plugin:@typescript-eslint/recommended-requiring-type-checking
|
|
||||||
rules:
|
|
||||||
"@typescript-eslint/comma-spacing":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/explicit-function-return-type":
|
|
||||||
- error
|
|
||||||
- allowExpressions: true
|
|
||||||
"@typescript-eslint/func-call-spacing":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/member-delimiter-style":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/indent":
|
|
||||||
- error
|
|
||||||
- 4
|
|
||||||
- SwitchCase: 0
|
|
||||||
"@typescript-eslint/prefer-nullish-coalescing":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/prefer-optional-chain":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/prefer-reduce-type-parameter":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/prefer-return-this-type":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/quotes":
|
|
||||||
- error
|
|
||||||
- single
|
|
||||||
"@typescript-eslint/type-annotation-spacing":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/semi":
|
|
||||||
- error
|
|
||||||
"@typescript-eslint/space-before-function-paren":
|
|
||||||
- error
|
|
||||||
- anonymous: never
|
|
||||||
named: never
|
|
||||||
asyncArrow: always
|
|
||||||
|
|
@ -15,6 +15,7 @@ export interface Block {
|
||||||
|
|
||||||
export interface Transaction {
|
export interface Transaction {
|
||||||
getChannelHeader(): common.ChannelHeader;
|
getChannelHeader(): common.ChannelHeader;
|
||||||
|
getCreator(): Uint8Array;
|
||||||
getValidationCode(): number;
|
getValidationCode(): number;
|
||||||
isValid(): boolean;
|
isValid(): boolean;
|
||||||
getNamespaceReadWriteSets(): NamespaceReadWriteSet[];
|
getNamespaceReadWriteSets(): NamespaceReadWriteSet[];
|
||||||
|
|
@ -46,6 +47,7 @@ export function parseBlock(block: common.Block): Block {
|
||||||
interface Payload {
|
interface Payload {
|
||||||
getChannelHeader(): common.ChannelHeader;
|
getChannelHeader(): common.ChannelHeader;
|
||||||
getEndorserTransaction(): EndorserTransaction;
|
getEndorserTransaction(): EndorserTransaction;
|
||||||
|
getSignatureHeader(): common.SignatureHeader;
|
||||||
getTransactionValidationCode(): number;
|
getTransactionValidationCode(): number;
|
||||||
isEndorserTransaction(): boolean;
|
isEndorserTransaction(): boolean;
|
||||||
isValid(): boolean;
|
isValid(): boolean;
|
||||||
|
|
@ -75,6 +77,7 @@ function parsePayload(payload: common.Payload, statusCode: number): Payload {
|
||||||
const transaction = peer.Transaction.deserializeBinary(payload.getData_asU8());
|
const transaction = peer.Transaction.deserializeBinary(payload.getData_asU8());
|
||||||
return parseEndorserTransaction(transaction);
|
return parseEndorserTransaction(transaction);
|
||||||
},
|
},
|
||||||
|
getSignatureHeader: cache(() => getSignatureHeader(payload)),
|
||||||
getTransactionValidationCode: () => statusCode,
|
getTransactionValidationCode: () => statusCode,
|
||||||
isEndorserTransaction,
|
isEndorserTransaction,
|
||||||
isValid: () => statusCode === peer.TxValidationCode.VALID,
|
isValid: () => statusCode === peer.TxValidationCode.VALID,
|
||||||
|
|
@ -103,6 +106,7 @@ function newTransaction(payload: Payload): Transaction {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getChannelHeader: () => payload.getChannelHeader(),
|
getChannelHeader: () => payload.getChannelHeader(),
|
||||||
|
getCreator: () => payload.getSignatureHeader().getCreator_asU8(),
|
||||||
getNamespaceReadWriteSets: () => transaction.getReadWriteSets()
|
getNamespaceReadWriteSets: () => transaction.getReadWriteSets()
|
||||||
.flatMap(readWriteSet => readWriteSet.getNamespaceReadWriteSets()),
|
.flatMap(readWriteSet => readWriteSet.getNamespaceReadWriteSets()),
|
||||||
getValidationCode: () => payload.getTransactionValidationCode(),
|
getValidationCode: () => payload.getTransactionValidationCode(),
|
||||||
|
|
@ -151,6 +155,11 @@ function getChannelHeader(payload: common.Payload): common.ChannelHeader {
|
||||||
return common.ChannelHeader.deserializeBinary(header.getChannelHeader_asU8());
|
return common.ChannelHeader.deserializeBinary(header.getChannelHeader_asU8());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSignatureHeader(payload: common.Payload): common.SignatureHeader {
|
||||||
|
const header = assertDefined(payload.getHeader(), 'Missing payload header');
|
||||||
|
return common.SignatureHeader.deserializeBinary(header.getSignatureHeader_asU8());
|
||||||
|
}
|
||||||
|
|
||||||
function getChaincodeActionPayloads(transaction: peer.Transaction): peer.ChaincodeActionPayload[] {
|
function getChaincodeActionPayloads(transaction: peer.Transaction): peer.ChaincodeActionPayload[] {
|
||||||
return transaction.getActionsList()
|
return transaction.getActionsList()
|
||||||
.map(transactionAction => transactionAction.getPayload_asU8())
|
.map(transactionAction => transactionAction.getPayload_asU8())
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue