All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hyperledger.fabric.shim.impl.InvocationStubImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2019 IBM All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package org.hyperledger.fabric.shim.impl;

import static java.util.stream.Collectors.toList;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.COMPLETED;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.GET_HISTORY_FOR_KEY;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.GET_PRIVATE_DATA_HASH;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.GET_QUERY_RESULT;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.GET_STATE_BY_RANGE;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Timestamp;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.hyperledger.fabric.protos.common.ChannelHeader;
import org.hyperledger.fabric.protos.common.Header;
import org.hyperledger.fabric.protos.common.HeaderType;
import org.hyperledger.fabric.protos.common.SignatureHeader;
import org.hyperledger.fabric.protos.ledger.queryresult.KV;
import org.hyperledger.fabric.protos.peer.ChaincodeEvent;
import org.hyperledger.fabric.protos.peer.ChaincodeID;
import org.hyperledger.fabric.protos.peer.ChaincodeInput;
import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
import org.hyperledger.fabric.protos.peer.ChaincodeProposalPayload;
import org.hyperledger.fabric.protos.peer.ChaincodeSpec;
import org.hyperledger.fabric.protos.peer.GetQueryResult;
import org.hyperledger.fabric.protos.peer.GetState;
import org.hyperledger.fabric.protos.peer.GetStateByRange;
import org.hyperledger.fabric.protos.peer.MetaDataKeys;
import org.hyperledger.fabric.protos.peer.Proposal;
import org.hyperledger.fabric.protos.peer.QueryMetadata;
import org.hyperledger.fabric.protos.peer.QueryResultBytes;
import org.hyperledger.fabric.protos.peer.Response;
import org.hyperledger.fabric.protos.peer.SignedProposal;
import org.hyperledger.fabric.protos.peer.StateMetadataResult;
import org.hyperledger.fabric.shim.Chaincode;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.CompositeKey;
import org.hyperledger.fabric.shim.ledger.KeyModification;
import org.hyperledger.fabric.shim.ledger.KeyValue;
import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata;

@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.GodClass"})
class InvocationStubImpl implements ChaincodeStub {

    private static final String UNSPECIFIED_START_KEY = new String(Character.toChars(0x000001));
    private static final String UNSPECIFIED_END_KEY = "";
    private static final Logger LOGGER = Logger.getLogger(InvocationStubImpl.class.getName());

    public static final String MAX_UNICODE_RUNE = "\udbff\udfff";
    private static final String CORE_PEER_LOCALMSPID = "CORE_PEER_LOCALMSPID";

    private static final Function
            QUERY_RESULT_BYTES_TO_KEY_MODIFICATION = queryResultBytes -> {
                try {
                    return org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.parseFrom(
                            queryResultBytes.getResultBytes());
                } catch (final InvalidProtocolBufferException e) {
                    throw new UncheckedIOException(e);
                }
            };
    private static final Function QUERY_RESULT_BYTES_TO_KV = queryResultBytes -> {
        try {
            return KV.parseFrom(queryResultBytes.getResultBytes());
        } catch (final InvalidProtocolBufferException e) {
            throw new UncheckedIOException(e);
        }
    };

    private final String channelId;
    private final String txId;
    private final ChaincodeInvocationTask handler;
    private final List args;
    private final SignedProposal signedProposal;
    private final Instant txTimestamp;
    private final ByteString creator;
    private final Map transientMap;
    private final byte[] binding;
    private ChaincodeEvent event;

    /**
     * @param message
     * @param handler
     * @throws InvalidProtocolBufferException
     */
    InvocationStubImpl(final ChaincodeMessage message, final ChaincodeInvocationTask handler)
            throws InvalidProtocolBufferException, NoSuchAlgorithmException {
        this.channelId = message.getChannelId();
        this.txId = message.getTxid();
        this.handler = handler;
        final ChaincodeInput input = ChaincodeInput.parseFrom(message.getPayload());

        this.args = Collections.unmodifiableList(input.getArgsList());
        this.signedProposal = message.getProposal();
        if (this.signedProposal.getProposalBytes().isEmpty()) {
            this.creator = null;
            this.txTimestamp = null;
            this.transientMap = Collections.emptyMap();
            this.binding = null;
        } else {
            final Proposal proposal = Proposal.parseFrom(signedProposal.getProposalBytes());
            final Header header = Header.parseFrom(proposal.getHeader());
            final ChannelHeader channelHeader = ChannelHeader.parseFrom(header.getChannelHeader());
            validateProposalType(channelHeader);
            final SignatureHeader signatureHeader = SignatureHeader.parseFrom(header.getSignatureHeader());
            final ChaincodeProposalPayload chaincodeProposalPayload =
                    ChaincodeProposalPayload.parseFrom(proposal.getPayload());
            final Timestamp timestamp = channelHeader.getTimestamp();

            this.txTimestamp = Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos());
            this.creator = signatureHeader.getCreator();
            this.transientMap = chaincodeProposalPayload.getTransientMapMap();
            this.binding = computeBinding(channelHeader, signatureHeader);
        }
    }

    private static boolean isEmptyString(final String str) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    private byte[] computeBinding(final ChannelHeader channelHeader, final SignatureHeader signatureHeader)
            throws NoSuchAlgorithmException {
        final MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        messageDigest.update(signatureHeader.getNonce().asReadOnlyByteBuffer());
        messageDigest.update(this.creator.asReadOnlyByteBuffer());
        final ByteBuffer epochBytes =
                ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(channelHeader.getEpoch());
        epochBytes.flip();
        messageDigest.update(epochBytes);
        return messageDigest.digest();
    }

    private void validateProposalType(final ChannelHeader channelHeader) {
        switch (HeaderType.forNumber(channelHeader.getType())) {
            case ENDORSER_TRANSACTION:
            case CONFIG:
                return;
            default:
                throw new IllegalArgumentException(String.format(
                        "Unexpected transaction type: %s", HeaderType.forNumber(channelHeader.getType())));
        }
    }

    @Override
    public List getArgs() {
        return args.stream().map(ByteString::toByteArray).collect(toList());
    }

    @Override
    public List getStringArgs() {
        return args.stream().map(ByteString::toStringUtf8).collect(toList());
    }

    @Override
    public String getFunction() {
        return getStringArgs().isEmpty() ? null : getStringArgs().get(0);
    }

    @Override
    public List getParameters() {
        return getStringArgs().stream().skip(1).collect(toList());
    }

    @Override
    public void setEvent(final String name, final byte[] payload) {
        if (null == name || isEmptyString(name)) {
            throw new IllegalArgumentException("event name can not be nil string");
        }
        if (payload != null) {
            this.event = ChaincodeEvent.newBuilder()
                    .setEventName(name)
                    .setPayload(ByteString.copyFrom(payload))
                    .build();
        } else {
            this.event = ChaincodeEvent.newBuilder().setEventName(name).build();
        }
    }

    @Override
    public ChaincodeEvent getEvent() {
        return event;
    }

    @Override
    public String getChannelId() {
        return channelId;
    }

    @Override
    public String getTxId() {
        return txId;
    }

    @Override
    public byte[] getState(final String key) {
        return this.handler
                .invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "", key))
                .toByteArray();
    }

    @Override
    @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
    public byte[] getStateValidationParameter(final String key) {

        final ByteString payload =
                handler.invoke(ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, "", key));
        try {
            final StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload);
            final Map stateMetadataMap = new HashMap<>();
            stateMetadataResult
                    .getEntriesList()
                    .forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue()));

            if (stateMetadataMap.containsKey(MetaDataKeys.VALIDATION_PARAMETER.toString())) {
                return stateMetadataMap
                        .get(MetaDataKeys.VALIDATION_PARAMETER.toString())
                        .toByteArray();
            }
        } catch (final InvalidProtocolBufferException e) {
            LOGGER.severe(() -> String.format("[%-8.8s] unmarshalling error", txId));
            throw new UncheckedIOException("Error unmarshalling StateMetadataResult.", e);
        }

        return null;
    }

    @Override
    public void putState(final String key, final byte[] value) {
        validateKey(key);
        this.handler.invoke(
                ChaincodeMessageFactory.newPutStateEventMessage(channelId, txId, "", key, ByteString.copyFrom(value)));
    }

    @Override
    public void setStateValidationParameter(final String key, final byte[] value) {
        validateKey(key);
        final ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMetadataEventMessage(
                channelId, txId, "", key, MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value));
        this.handler.invoke(msg);
    }

    @Override
    public void delState(final String key) {
        final ChaincodeMessage msg = ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, "", key);
        this.handler.invoke(msg);
    }

    @Override
    public QueryResultsIterator getStateByRange(final String startKey, final String endKey) {
        String start = startKey;
        String end = endKey;

        if (startKey == null || startKey.isEmpty()) {
            start = UNSPECIFIED_START_KEY;
        }
        if (endKey == null) {
            end = UNSPECIFIED_END_KEY;
        }
        CompositeKey.validateSimpleKeys(start, end);

        return executeGetStateByRange("", start, end);
    }

    private QueryResultsIterator executeGetStateByRange(
            final String collection, final String startKey, final String endKey) {

        final ByteString requestPayload = GetStateByRange.newBuilder()
                .setCollection(collection)
                .setStartKey(startKey)
                .setEndKey(endKey)
                .build()
                .toByteString();

        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, requestPayload);
        final ByteString response = handler.invoke(requestMessage);

        return new QueryResultsIteratorImpl<>(
                this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new));
    }

    @Override
    public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(
            final String startKey, final String endKey, final int pageSize, final String bookmark) {

        String start = startKey;
        String end = endKey;

        if (startKey == null || startKey.isEmpty()) {
            start = UNSPECIFIED_START_KEY;
        }
        if (endKey == null) {
            end = UNSPECIFIED_END_KEY;
        }

        CompositeKey.validateSimpleKeys(start, end);

        final QueryMetadata queryMetadata = QueryMetadata.newBuilder()
                .setBookmark(bookmark)
                .setPageSize(pageSize)
                .build();

        return executeGetStateByRangeWithMetadata("", start, end, queryMetadata.toByteString());
    }

    private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWithMetadata(
            final String collection, final String startKey, final String endKey, final ByteString metadata) {

        final ByteString payload = GetStateByRange.newBuilder()
                .setCollection(collection)
                .setStartKey(startKey)
                .setEndKey(endKey)
                .setMetadata(metadata)
                .build()
                .toByteString();

        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, payload);

        final ByteString response = this.handler.invoke(requestMessage);

        return new QueryResultsIteratorWithMetadataImpl<>(
                this.handler, getChannelId(), getTxId(), response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new));
    }

    @Override
    public QueryResultsIterator getStateByPartialCompositeKey(final String compositeKey) {

        CompositeKey key;

        if (compositeKey.startsWith(CompositeKey.NAMESPACE)) {
            key = CompositeKey.parseCompositeKey(compositeKey);
        } else {
            key = new CompositeKey(compositeKey);
        }

        return getStateByPartialCompositeKey(key);
    }

    @Override
    public QueryResultsIterator getStateByPartialCompositeKey(
            final String objectType, final String... attributes) {
        return getStateByPartialCompositeKey(new CompositeKey(objectType, attributes));
    }

    @Override
    public QueryResultsIterator getStateByPartialCompositeKey(final CompositeKey compositeKey) {

        String cKeyAsString;

        if (compositeKey == null) {
            cKeyAsString = new CompositeKey(UNSPECIFIED_START_KEY).toString();
        } else {
            cKeyAsString = compositeKey.toString();
        }

        return executeGetStateByRange("", cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE);
    }

    @Override
    public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(
            final CompositeKey compositeKey, final int pageSize, final String bookmark) {

        String cKeyAsString;

        if (compositeKey == null) {
            cKeyAsString = new CompositeKey(UNSPECIFIED_START_KEY).toString();
        } else {
            cKeyAsString = compositeKey.toString();
        }

        final QueryMetadata queryMetadata = QueryMetadata.newBuilder()
                .setBookmark(bookmark)
                .setPageSize(pageSize)
                .build();

        return executeGetStateByRangeWithMetadata(
                "", cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE, queryMetadata.toByteString());
    }

    @Override
    public CompositeKey createCompositeKey(final String objectType, final String... attributes) {
        return new CompositeKey(objectType, attributes);
    }

    @Override
    public CompositeKey splitCompositeKey(final String compositeKey) {
        return CompositeKey.parseCompositeKey(compositeKey);
    }

    @Override
    public QueryResultsIterator getQueryResult(final String query) {

        final ByteString requestPayload = GetQueryResult.newBuilder()
                .setCollection("")
                .setQuery(query)
                .build()
                .toByteString();
        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload);
        final ByteString response = handler.invoke(requestMessage);

        return new QueryResultsIteratorImpl<>(
                this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new));
    }

    @Override
    public QueryResultsIteratorWithMetadata getQueryResultWithPagination(
            final String query, final int pageSize, final String bookmark) {

        final ByteString queryMetadataPayload = QueryMetadata.newBuilder()
                .setBookmark(bookmark)
                .setPageSize(pageSize)
                .build()
                .toByteString();
        final ByteString requestPayload = GetQueryResult.newBuilder()
                .setCollection("")
                .setQuery(query)
                .setMetadata(queryMetadataPayload)
                .build()
                .toByteString();
        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload);
        final ByteString response = handler.invoke(requestMessage);

        return new QueryResultsIteratorWithMetadataImpl<>(
                this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new));
    }

    @Override
    public QueryResultsIterator getHistoryForKey(final String key) {

        final ByteString requestPayload = GetQueryResult.newBuilder()
                .setCollection("")
                .setQuery(key)
                .build()
                .toByteString();
        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_HISTORY_FOR_KEY, channelId, txId, requestPayload);
        final ByteString response = handler.invoke(requestMessage);

        return new QueryResultsIteratorImpl<>(
                this.handler,
                channelId,
                txId,
                response,
                QUERY_RESULT_BYTES_TO_KEY_MODIFICATION.andThen(KeyModificationImpl::new));
    }

    @Override
    public byte[] getPrivateData(final String collection, final String key) {
        validateCollection(collection);
        return this.handler
                .invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, collection, key))
                .toByteArray();
    }

    @Override
    public byte[] getPrivateDataHash(final String collection, final String key) {

        validateCollection(collection);

        final ByteString requestPayload = GetState.newBuilder()
                .setCollection(collection)
                .setKey(key)
                .build()
                .toByteString();
        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_PRIVATE_DATA_HASH, channelId, txId, requestPayload);

        return handler.invoke(requestMessage).toByteArray();
    }

    @Override
    @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
    public byte[] getPrivateDataValidationParameter(final String collection, final String key) {
        validateCollection(collection);

        final ByteString payload = handler.invoke(
                ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, collection, key));
        try {
            final StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload);
            final Map stateMetadataMap = new HashMap<>();
            stateMetadataResult
                    .getEntriesList()
                    .forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue()));

            if (stateMetadataMap.containsKey(MetaDataKeys.VALIDATION_PARAMETER.toString())) {
                return stateMetadataMap
                        .get(MetaDataKeys.VALIDATION_PARAMETER.toString())
                        .toByteArray();
            }
        } catch (final InvalidProtocolBufferException e) {
            LOGGER.severe(() -> String.format("[%-8.8s] unmarshalling error", txId));
            throw new UncheckedIOException("Error unmarshalling StateMetadataResult.", e);
        }

        return null;
    }

    @Override
    public void putPrivateData(final String collection, final String key, final byte[] value) {
        validateKey(key);
        validateCollection(collection);
        this.handler.invoke(ChaincodeMessageFactory.newPutStateEventMessage(
                channelId, txId, collection, key, ByteString.copyFrom(value)));
    }

    @Override
    public void setPrivateDataValidationParameter(final String collection, final String key, final byte[] value) {
        validateKey(key);
        validateCollection(collection);
        final ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMetadataEventMessage(
                channelId,
                txId,
                collection,
                key,
                MetaDataKeys.VALIDATION_PARAMETER.toString(),
                ByteString.copyFrom(value));
        this.handler.invoke(msg);
    }

    @Override
    public void delPrivateData(final String collection, final String key) {
        validateCollection(collection);
        final ChaincodeMessage msg =
                ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, collection, key);
        this.handler.invoke(msg);
    }

    @Override
    public void purgePrivateData(final String collection, final String key) {
        validateCollection(collection);
        final ChaincodeMessage msg =
                ChaincodeMessageFactory.newPurgeStateEventMessage(channelId, txId, collection, key);
        this.handler.invoke(msg);
    }

    @Override
    public QueryResultsIterator getPrivateDataByRange(
            final String collection, final String startKey, final String endKey) {
        String start = startKey;
        String end = endKey;

        validateCollection(collection);
        if (startKey == null || startKey.isEmpty()) {
            start = UNSPECIFIED_START_KEY;
        }
        if (endKey == null) {
            end = UNSPECIFIED_END_KEY;
        }
        CompositeKey.validateSimpleKeys(start, end);

        return executeGetStateByRange(collection, start, end);
    }

    @Override
    public QueryResultsIterator getPrivateDataByPartialCompositeKey(
            final String collection, final String compositeKey) {

        CompositeKey key;

        if (compositeKey == null) {
            key = new CompositeKey("");
        } else if (compositeKey.startsWith(CompositeKey.NAMESPACE)) {
            key = CompositeKey.parseCompositeKey(compositeKey);
        } else {
            key = new CompositeKey(compositeKey);
        }

        return getPrivateDataByPartialCompositeKey(collection, key);
    }

    @Override
    public QueryResultsIterator getPrivateDataByPartialCompositeKey(
            final String collection, final CompositeKey compositeKey) {
        String cKeyAsString;
        if (compositeKey == null) {
            cKeyAsString = new CompositeKey(UNSPECIFIED_START_KEY).toString();
        } else {
            cKeyAsString = compositeKey.toString();
        }

        return executeGetStateByRange(collection, cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE);
    }

    @Override
    public QueryResultsIterator getPrivateDataByPartialCompositeKey(
            final String collection, final String objectType, final String... attributes) {
        return getPrivateDataByPartialCompositeKey(collection, new CompositeKey(objectType, attributes));
    }

    @Override
    public QueryResultsIterator getPrivateDataQueryResult(final String collection, final String query) {
        validateCollection(collection);
        final ByteString requestPayload = GetQueryResult.newBuilder()
                .setCollection(collection)
                .setQuery(query)
                .build()
                .toByteString();
        final ChaincodeMessage requestMessage =
                ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload);
        final ByteString response = handler.invoke(requestMessage);

        return new QueryResultsIteratorImpl<>(
                this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new));
    }

    @Override
    public Chaincode.Response invokeChaincode(
            final String chaincodeName, final List args, final String channel) {
        // internally we handle chaincode name as a composite name
        final String compositeName;
        if (channel != null && !isEmptyString(channel)) {
            compositeName = chaincodeName + "/" + channel;
        } else {
            compositeName = chaincodeName;
        }

        // create invocation specification of the chaincode to invoke
        final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder()
                .setChaincodeId(ChaincodeID.newBuilder().setName(compositeName).build())
                .setInput(ChaincodeInput.newBuilder()
                        .addAllArgs(args.stream().map(ByteString::copyFrom).collect(toList()))
                        .build())
                .build()
                .toByteString();

        final ChaincodeMessage invokeChaincodeMessage =
                ChaincodeMessageFactory.newInvokeChaincodeMessage(this.channelId, this.txId, invocationSpecPayload);
        final ByteString response = this.handler.invoke(invokeChaincodeMessage);

        try {
            // response message payload should be yet another chaincode
            // message (the actual response message)
            final ChaincodeMessage responseMessage = ChaincodeMessage.parseFrom(response);
            // the actual response message must be of type COMPLETED

            LOGGER.fine(() -> String.format(
                    "[%-8.8s] %s response received from other chaincode.", txId, responseMessage.getType()));

            if (responseMessage.getType() == COMPLETED) {
                // success
                final Response r = Response.parseFrom(responseMessage.getPayload());
                return new Chaincode.Response(
                        Chaincode.Response.Status.forCode(r.getStatus()),
                        r.getMessage(),
                        r.getPayload().toByteArray());
            } else {
                // error
                final String message = responseMessage.getPayload().toStringUtf8();
                return new Chaincode.Response(Chaincode.Response.Status.INTERNAL_SERVER_ERROR, message, null);
            }
        } catch (final InvalidProtocolBufferException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Override
    public SignedProposal getSignedProposal() {
        return signedProposal;
    }

    @Override
    public Instant getTxTimestamp() {
        return txTimestamp;
    }

    @Override
    @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
    public byte[] getCreator() {
        if (creator == null) {
            return null;
        }
        return creator.toByteArray();
    }

    @Override
    public Map getTransient() {
        return transientMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, x -> x.getValue().toByteArray()));
    }

    @Override
    @SuppressWarnings("PMD.MethodReturnsInternalArray")
    public byte[] getBinding() {
        return this.binding;
    }

    private void validateKey(final String key) {
        Objects.requireNonNull(key, "key cannot be null");
        if (key.isEmpty()) {
            throw new IllegalArgumentException("key cannot not be an empty string");
        }
    }

    private void validateCollection(final String collection) {
        Objects.requireNonNull(collection, "collection cannot be null");
        if (collection.isEmpty()) {
            throw new IllegalArgumentException("collection must not be an empty string");
        }
    }

    @Override
    public String getMspId() {
        if (System.getenv().containsKey(CORE_PEER_LOCALMSPID)) {
            return System.getenv(CORE_PEER_LOCALMSPID);
        }
        throw new IllegalStateException("CORE_PEER_LOCALMSPID is unset in chaincode process");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy