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

com.scalar.dl.client.service.LedgerClient Maven / Gradle / Ivy

There is a newer version: 3.10.0
Show newest version
/*
 * This file is part of the Scalar DL client SDK.
 * Copyright (c) 2019 Scalar, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. For more information, please contact Scalar, Inc.
 */
package com.scalar.dl.client.service;

import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.scalar.dl.client.exception.ClientException;
import com.scalar.dl.ledger.asset.AssetProof;
import com.scalar.dl.ledger.database.TransactionState;
import com.scalar.dl.ledger.model.ContractExecutionResult;
import com.scalar.dl.ledger.model.LedgerValidationResult;
import com.scalar.dl.ledger.model.LedgersValidationResult;
import com.scalar.dl.ledger.rpc.ClientUtil;
import com.scalar.dl.ledger.service.StatusCode;
import com.scalar.dl.ledger.service.ThrowableConsumer;
import com.scalar.dl.ledger.service.ThrowableFunction;
import com.scalar.dl.ledger.util.JsonpSerDe;
import com.scalar.dl.rpc.AssetProofRetrievalRequest;
import com.scalar.dl.rpc.AssetProofRetrievalResponse;
import com.scalar.dl.rpc.CertificateRegistrationRequest;
import com.scalar.dl.rpc.ContractExecutionRequest;
import com.scalar.dl.rpc.ContractExecutionResponse;
import com.scalar.dl.rpc.ContractRegistrationRequest;
import com.scalar.dl.rpc.ContractsListingRequest;
import com.scalar.dl.rpc.ExecutionAbortRequest;
import com.scalar.dl.rpc.ExecutionAbortResponse;
import com.scalar.dl.rpc.FunctionRegistrationRequest;
import com.scalar.dl.rpc.LedgerGrpc;
import com.scalar.dl.rpc.LedgerPrivilegedGrpc;
import com.scalar.dl.rpc.LedgerValidationRequest;
import com.scalar.dl.rpc.LedgerValidationResponse;
import com.scalar.dl.rpc.LedgersValidationRequest;
import io.grpc.ManagedChannel;
import io.grpc.netty.NettyChannelBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.concurrent.Immutable;
import javax.json.Json;
import javax.json.JsonObject;
import javax.net.ssl.SSLException;

@Immutable
public class LedgerClient extends AbstractLedgerClient {
  private final ManagedChannel channel;
  private final ManagedChannel privilegedChannel;
  private final LedgerGrpc.LedgerBlockingStub ledgerStub;
  private final LedgerPrivilegedGrpc.LedgerPrivilegedBlockingStub ledgerPrivilegedStub;

  @Inject
  public LedgerClient(com.scalar.dl.ledger.config.ClientConfig config) throws SSLException {
    NettyChannelBuilder builder =
        NettyChannelBuilder.forAddress(config.getLedgerHost(), config.getLedgerPort());

    ClientUtil.configureTls(builder, config.isTlsEnabled(), config.getTlsCaRootCert());
    ClientUtil.configureHeader(builder, config.getAuthorizationCredential());

    channel = builder.build();
    ledgerStub = LedgerGrpc.newBlockingStub(channel);

    privilegedChannel =
        NettyChannelBuilder.forAddress(config.getLedgerHost(), config.getLedgerPrivilegedPort())
            .usePlaintext()
            .build();
    ledgerPrivilegedStub = LedgerPrivilegedGrpc.newBlockingStub(privilegedChannel);
  }

  @VisibleForTesting
  LedgerClient(
      LedgerGrpc.LedgerBlockingStub ledgerStub,
      LedgerPrivilegedGrpc.LedgerPrivilegedBlockingStub ledgerPrivilegedStub) {
    this.channel = null;
    this.privilegedChannel = null;
    this.ledgerStub = ledgerStub;
    this.ledgerPrivilegedStub = ledgerPrivilegedStub;
  }

  @Override
  public void shutdown() {
    try {
      channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      throw new ClientException(e.getMessage(), e, StatusCode.RUNTIME_ERROR);
    }
  }

  @Override
  public void register(CertificateRegistrationRequest request) {
    ThrowableConsumer f =
        r -> ledgerPrivilegedStub.registerCert(request);
    try {
      accept(f, request);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
  }

  @Override
  public void register(FunctionRegistrationRequest request) {
    ThrowableConsumer f =
        r -> ledgerPrivilegedStub.registerFunction(request);
    try {
      accept(f, request);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
  }

  @Override
  public void register(ContractRegistrationRequest request) {
    ThrowableConsumer f = r -> ledgerStub.registerContract(request);
    try {
      accept(f, request);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
  }

  @Override
  public JsonObject list(ContractsListingRequest request) {
    try {
      String jsonString = ledgerStub.listContracts(request).getJson();
      return jsonString.isEmpty()
          ? Json.createObjectBuilder().build()
          : new JsonpSerDe().deserialize(jsonString);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
    // Java compiler requires this line even though it won't come here
    return Json.createObjectBuilder().build();
  }

  @Override
  public ContractExecutionResult execute(ContractExecutionRequest request) {
    return execute(request, DEFAULT_AUDITING_HOOK);
  }

  @Override
  public ContractExecutionResult execute(
      ContractExecutionRequest request,
      ThrowableFunction auditingHook) {
    try {
      ContractExecutionResponse response = ledgerStub.executeContract(request);
      ContractExecutionResponse auditorResponse = auditingHook.apply(response);

      JsonObject result =
          response.getResult().isEmpty()
              ? null
              : new JsonpSerDe().deserialize(response.getResult());
      List proofs = new ArrayList<>();
      response.getProofsList().forEach(p -> proofs.add(new AssetProof(p)));

      List auditorProofs = null;
      if (auditorResponse != null) {
        auditorProofs =
            auditorResponse.getProofsList().stream()
                .map(AssetProof::new)
                .collect(Collectors.toList());
      }

      return new ContractExecutionResult(result, proofs, auditorProofs);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
    // Java compiler requires this line even though it won't come here
    return new ContractExecutionResult(null, null, null);
  }

  @Override
  public LedgerValidationResult validate(LedgerValidationRequest request) {
    try {
      LedgerValidationResponse response = ledgerStub.validateLedger(request);
      AssetProof proof = response.hasProof() ? new AssetProof(response.getProof()) : null;
      return new LedgerValidationResult(StatusCode.get(response.getStatusCode()), proof);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
    // Java compiler requires this line even though it won't come here
    return new LedgerValidationResult(StatusCode.RUNTIME_ERROR, null);
  }

  @Override
  public LedgersValidationResult validate(LedgersValidationRequest request) {
    throw new RuntimeException("not supported for now");
  }

  @Override
  public Optional retrieve(AssetProofRetrievalRequest request) {
    try {
      AssetProofRetrievalResponse response = ledgerStub.retrieveAssetProof(request);
      AssetProof proof = response.hasProof() ? new AssetProof(response.getProof()) : null;
      return Optional.ofNullable(proof);
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
    // Java compiler requires this line even though it won't come here
    return Optional.empty();
  }

  @Override
  public TransactionState abort(ExecutionAbortRequest request) {
    try {
      ExecutionAbortResponse response = ledgerStub.abortExecution(request);
      return TransactionState.getInstance(response.getState().getNumber());
    } catch (Exception e) {
      throwExceptionWithStatusCode(e);
    }
    // Java compiler requires this line even though it won't come here
    return TransactionState.UNKNOWN;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy