diff --git a/internal/blockchain/ethereum/quorum/geth_provider.go b/internal/blockchain/ethereum/quorum/geth_provider.go index 1bd2bedd..bcc52262 100644 --- a/internal/blockchain/ethereum/quorum/geth_provider.go +++ b/internal/blockchain/ethereum/quorum/geth_provider.go @@ -244,7 +244,7 @@ func (p *GethProvider) GetDockerServiceDefinitions() []*docker.ServiceDefinition ContainerName: fmt.Sprintf("member%dtessera", i), Volumes: []string{fmt.Sprintf("tessera_%d:/data", i)}, Logging: docker.StandardLogOptions, - Ports: []string{fmt.Sprintf("%d:%s", p.stack.ExposedPtmPort+(i*exposedBlockchainPortMultiplier), ethereum.TmTpPort)}, // defaults 4100, 4110, 4120, 4130 + Ports: []string{fmt.Sprintf("%d:%s", p.stack.ExposedPtmPort+(i*exposedBlockchainPortMultiplier), TmTpPort)}, // defaults 4100, 4110, 4120, 4130 Environment: p.stack.EnvironmentVars, EntryPoint: []string{"/bin/sh", "-c", "/data/docker-entrypoint.sh"}, Deploy: map[string]interface{}{"restart_policy": map[string]string{"condition": "on-failure", "max_attempts": "3"}}, @@ -340,21 +340,21 @@ func (p *GethProvider) CreateAccount(args []string) (interface{}, error) { if p.stack.TesseraEnabled { tesseraVolumeName := fmt.Sprintf("%s_tessera_%s", p.stack.Name, memberIndex) tesseraKeysOutputDirectory := filepath.Join(directory, "tessera", fmt.Sprintf("tessera_%s", memberIndex), "keystore") - _, tesseraPubKey, tesseraKeysPath, err = ethereum.CreateTesseraKeys(p.ctx, tesseraImage, tesseraKeysOutputDirectory, "", "tm", keyPassword) + _, tesseraPubKey, tesseraKeysPath, err = CreateTesseraKeys(p.ctx, tesseraImage, tesseraKeysOutputDirectory, "", "tm", keyPassword) if err != nil { return nil, err } l.Info(fmt.Sprintf("keys generated in %s", tesseraKeysPath)) - l.Info(fmt.Sprintf("generating tessera entrypoint file for member %s", memberIndex)) + l.Info(fmt.Sprintf("generating tessera docker-entrypoint file for member %s", memberIndex)) tesseraEntrypointOutputDirectory := filepath.Join(directory, "tessera", fmt.Sprintf("tessera_%s", memberIndex)) - if err := ethereum.CreateTesseraEntrypoint(p.ctx, tesseraEntrypointOutputDirectory, tesseraVolumeName, memberCount); err != nil { + if err := CreateTesseraEntrypoint(p.ctx, tesseraEntrypointOutputDirectory, tesseraVolumeName, memberCount); err != nil { return nil, err } } - l.Info(fmt.Sprintf("generating quorum entrypoint file for member %s", memberIndex)) + l.Info(fmt.Sprintf("generating quorum docker-entrypoint file for member %s", memberIndex)) quorumEntrypointOutputDirectory := filepath.Join(directory, "blockchain", fmt.Sprintf("geth_%s", memberIndex)) - if err := ethereum.CreateQuorumEntrypoint(p.ctx, quorumEntrypointOutputDirectory, gethVolumeName, memberIndex, p.stack.QuorumConsensus.String(), int(p.stack.ChainID()), p.stack.TesseraEnabled); err != nil { + if err := CreateQuorumEntrypoint(p.ctx, quorumEntrypointOutputDirectory, gethVolumeName, memberIndex, p.stack.QuorumConsensus.String(), int(p.stack.ChainID()), p.stack.TesseraEnabled); err != nil { return nil, err } @@ -369,7 +369,7 @@ func (p *GethProvider) CreateAccount(args []string) (interface{}, error) { return nil, err } } - if err := ethereum.CopyQuorumEntrypointToVolume(p.ctx, quorumEntrypointOutputDirectory, gethVolumeName); err != nil { + if err := CopyQuorumEntrypointToVolume(p.ctx, quorumEntrypointOutputDirectory, gethVolumeName); err != nil { return nil, err } } diff --git a/internal/blockchain/ethereum/private_transaction_manager.go b/internal/blockchain/ethereum/quorum/private_transaction_manager.go similarity index 56% rename from internal/blockchain/ethereum/private_transaction_manager.go rename to internal/blockchain/ethereum/quorum/private_transaction_manager.go index 64ae6933..a5587375 100644 --- a/internal/blockchain/ethereum/private_transaction_manager.go +++ b/internal/blockchain/ethereum/quorum/private_transaction_manager.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ethereum +package quorum import ( "context" @@ -167,89 +167,3 @@ func CopyTesseraEntrypointToVolume(ctx context.Context, tesseraEntrypointDirecto } return nil } - -func CreateQuorumEntrypoint(ctx context.Context, outputDirectory, volumeName, memberIndex, consensus string, chainId int, tesseraEnabled bool) error { - discoveryCmd := "BOOTNODE_CMD=\"\"" - connectTimeout := 15 - if memberIndex != "0" { - discoveryCmd = fmt.Sprintf(`bootnode=$(curl http://geth_0:%s -s --connect-timeout %[2]d --max-time %[2]d --retry 5 --retry-connrefused --retry-delay 0 --retry-max-time 60 --fail --header "Content-Type: application/json" --data '{"jsonrpc":"2.0", "method": "admin_nodeInfo", "params": [], "id": 1}' | grep -o "enode://[a-z0-9@.:]*") -BOOTNODE_CMD="--bootnodes $bootnode" -BOOTNODE_CMD=${BOOTNODE_CMD/127.0.0.1/geth_0}`, GethPort, connectTimeout) - } - - tesseraCmd := "" - if tesseraEnabled { - tesseraCmd = fmt.Sprintf(`TESSERA_URL=http://member%stessera -TESSERA_TP_PORT=%s -TESSERA_Q2T_PORT=%s -TESSERA_UPCHECK_URL=$TESSERA_URL:$TESSERA_TP_PORT/upcheck -ADDITIONAL_ARGS="${ADDITIONAL_ARGS:-} --ptm.timeout 5 --ptm.url ${TESSERA_URL}:${TESSERA_Q2T_PORT} --ptm.http.writebuffersize 4096 --ptm.http.readbuffersize 4096 --ptm.tls.mode off" - -echo -n "Checking tessera is up ... " -curl --connect-timeout %[4]d --max-time %[4]d --retry 5 --retry-connrefused --retry-delay 0 --retry-max-time 60 --silent --fail "$TESSERA_UPCHECK_URL" -echo "" -`, memberIndex, TmTpPort, TmQ2tPort, connectTimeout) - } - - content := fmt.Sprintf(`#!/bin/sh - -set -o errexit -set -o nounset -set -o pipefail -set -o xtrace - -GOQUORUM_CONS_ALGO=%s -if [ "istanbul" == "$GOQUORUM_CONS_ALGO" ]; -then - echo "Using istanbul for consensus algorithm..." - export CONSENSUS_ARGS="--istanbul.blockperiod 5 --mine --miner.threads 1 --miner.gasprice 0 --emitcheckpoints" - export QUORUM_API="istanbul" -elif [ "qbft" == "$GOQUORUM_CONS_ALGO" ]; -then - echo "Using qbft for consensus algorithm..." - export CONSENSUS_ARGS="--mine --miner.threads 1 --miner.gasprice 0 --emitcheckpoints" - export QUORUM_API="istanbul" -elif [ "raft" == "$GOQUORUM_CONS_ALGO" ]; -then - echo "Using raft for consensus algorithm..." - export CONSENSUS_ARGS="--raft --raftblocktime 300 --raftport 53000" - export QUORUM_API="raft" -elif [ "clique" == "$GOQUORUM_CONS_ALGO" ]; -then - echo "Using clique for consensus algorithm..." - export CONSENSUS_ARGS="" - export QUORUM_API="clique" -fi - -ADDITIONAL_ARGS=${ADDITIONAL_ARGS:-} -%s - -# discovery -%s -echo "bootnode discovery command :: $BOOTNODE_CMD" -IP_ADDR=$(cat /etc/hosts | tail -n 1 | awk '{print $1}') - -exec geth --datadir /data --nat extip:$IP_ADDR --syncmode 'full' --revertreason --port 30311 --http --http.addr "0.0.0.0" --http.corsdomain="*" -http.port %s --http.vhosts "*" --http.api admin,personal,eth,net,web3,txpool,miner,debug,$QUORUM_API --networkid %d --miner.gasprice 0 --password /data/password --mine --allow-insecure-unlock --verbosity 4 $CONSENSUS_ARGS --miner.gaslimit 16777215 $BOOTNODE_CMD $ADDITIONAL_ARGS`, consensus, tesseraCmd, discoveryCmd, GethPort, chainId) - filename := filepath.Join(outputDirectory, entrypoint) - if err := os.MkdirAll(outputDirectory, 0755); err != nil { - return err - } - file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - return err - } - defer file.Close() - _, err = file.WriteString(content) - if err != nil { - return err - } - CopyQuorumEntrypointToVolume(ctx, outputDirectory, volumeName) - return nil -} - -func CopyQuorumEntrypointToVolume(ctx context.Context, quorumEntrypointDirectory, volumeName string) error { - if err := docker.CopyFileToVolume(ctx, volumeName, filepath.Join(quorumEntrypointDirectory, entrypoint), ""); err != nil { - return err - } - return nil -} diff --git a/internal/blockchain/ethereum/quorum/quorum.go b/internal/blockchain/ethereum/quorum/quorum.go new file mode 100644 index 00000000..0cbd623e --- /dev/null +++ b/internal/blockchain/ethereum/quorum/quorum.go @@ -0,0 +1,112 @@ +// Copyright © 2024 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package quorum + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "github.com/hyperledger/firefly-cli/internal/docker" +) + +func CreateQuorumEntrypoint(ctx context.Context, outputDirectory, volumeName, memberIndex, consensus string, chainId int, tesseraEnabled bool) error { + discoveryCmd := "BOOTNODE_CMD=\"\"" + connectTimeout := 15 + if memberIndex != "0" { + discoveryCmd = fmt.Sprintf(`bootnode=$(curl http://geth_0:%s -s --connect-timeout %[2]d --max-time %[2]d --retry 5 --retry-connrefused --retry-delay 0 --retry-max-time 60 --fail --header "Content-Type: application/json" --data '{"jsonrpc":"2.0", "method": "admin_nodeInfo", "params": [], "id": 1}' | grep -o "enode://[a-z0-9@.:]*") +BOOTNODE_CMD="--bootnodes $bootnode" +BOOTNODE_CMD=${BOOTNODE_CMD/127.0.0.1/geth_0}`, GethPort, connectTimeout) + } + + tesseraCmd := "" + if tesseraEnabled { + tesseraCmd = fmt.Sprintf(`TESSERA_URL=http://member%stessera +TESSERA_TP_PORT=%s +TESSERA_Q2T_PORT=%s +TESSERA_UPCHECK_URL=$TESSERA_URL:$TESSERA_TP_PORT/upcheck +ADDITIONAL_ARGS="${ADDITIONAL_ARGS:-} --ptm.timeout 5 --ptm.url ${TESSERA_URL}:${TESSERA_Q2T_PORT} --ptm.http.writebuffersize 4096 --ptm.http.readbuffersize 4096 --ptm.tls.mode off" + +echo -n "Checking tessera is up ... " +curl --connect-timeout %[4]d --max-time %[4]d --retry 5 --retry-connrefused --retry-delay 0 --retry-max-time 60 --silent --fail "$TESSERA_UPCHECK_URL" +echo "" +`, memberIndex, TmTpPort, TmQ2tPort, connectTimeout) + } + + content := fmt.Sprintf(`#!/bin/sh + +set -o errexit +set -o nounset +set -o pipefail +set -o xtrace + +GOQUORUM_CONS_ALGO=%s +if [ "istanbul" == "$GOQUORUM_CONS_ALGO" ]; +then + echo "Using istanbul for consensus algorithm..." + export CONSENSUS_ARGS="--istanbul.blockperiod 5 --mine --miner.threads 1 --miner.gasprice 0 --emitcheckpoints" + export QUORUM_API="istanbul" +elif [ "qbft" == "$GOQUORUM_CONS_ALGO" ]; +then + echo "Using qbft for consensus algorithm..." + export CONSENSUS_ARGS="--mine --miner.threads 1 --miner.gasprice 0 --emitcheckpoints" + export QUORUM_API="istanbul" +elif [ "raft" == "$GOQUORUM_CONS_ALGO" ]; +then + echo "Using raft for consensus algorithm..." + export CONSENSUS_ARGS="--raft --raftblocktime 300 --raftport 53000" + export QUORUM_API="raft" +elif [ "clique" == "$GOQUORUM_CONS_ALGO" ]; +then + echo "Using clique for consensus algorithm..." + export CONSENSUS_ARGS="" + export QUORUM_API="clique" +fi + +ADDITIONAL_ARGS=${ADDITIONAL_ARGS:-} +%s + +# discovery +%s +echo "bootnode discovery command :: $BOOTNODE_CMD" +IP_ADDR=$(cat /etc/hosts | tail -n 1 | awk '{print $1}') + +exec geth --datadir /data --nat extip:$IP_ADDR --syncmode 'full' --revertreason --port 30311 --http --http.addr "0.0.0.0" --http.corsdomain="*" -http.port %s --http.vhosts "*" --http.api admin,personal,eth,net,web3,txpool,miner,debug,$QUORUM_API --networkid %d --miner.gasprice 0 --password /data/password --mine --allow-insecure-unlock --verbosity 4 $CONSENSUS_ARGS --miner.gaslimit 16777215 $BOOTNODE_CMD $ADDITIONAL_ARGS`, consensus, tesseraCmd, discoveryCmd, GethPort, chainId) + filename := filepath.Join(outputDirectory, entrypoint) + if err := os.MkdirAll(outputDirectory, 0755); err != nil { + return err + } + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return err + } + defer file.Close() + _, err = file.WriteString(content) + if err != nil { + return err + } + CopyQuorumEntrypointToVolume(ctx, outputDirectory, volumeName) + return nil +} + +func CopyQuorumEntrypointToVolume(ctx context.Context, quorumEntrypointDirectory, volumeName string) error { + if err := docker.CopyFileToVolume(ctx, volumeName, filepath.Join(quorumEntrypointDirectory, entrypoint), ""); err != nil { + return err + } + return nil +}