Merge pull request #502 from nspcc-dev/docker-compose-environment-for-neo-go
Create docker-compose environment
This commit is contained in:
commit
5076704019
11 changed files with 193 additions and 108 deletions
|
@ -82,10 +82,11 @@ jobs:
|
|||
working_directory: /go/src/github.com/CityOfZion/neo-go
|
||||
executor: go1_12
|
||||
docker:
|
||||
- image: alpine
|
||||
- image: golang:1-alpine
|
||||
steps:
|
||||
- run: apk update && apk add git make curl tar
|
||||
- checkout
|
||||
- gomod
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
name: Install Docker client
|
||||
|
|
75
.docker/docker-compose.yml
Normal file
75
.docker/docker-compose.yml
Normal file
|
@ -0,0 +1,75 @@
|
|||
version: '2.4'
|
||||
|
||||
networks:
|
||||
neo_go_network:
|
||||
name: neo_go_network
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.200.0.0/24
|
||||
gateway: 172.200.0.254
|
||||
|
||||
volumes:
|
||||
volume_chain:
|
||||
driver: local
|
||||
|
||||
services:
|
||||
node_one:
|
||||
container_name: neo_go_node_one
|
||||
image: env_neo_go_image
|
||||
command: "node --config-path /config --privnet"
|
||||
volumes:
|
||||
- ../config/protocol.privnet.docker.one.yml:/config/protocol.privnet.yml
|
||||
- volume_chain:/chains
|
||||
networks:
|
||||
neo_go_network:
|
||||
ipv4_address: 172.200.0.1
|
||||
ports:
|
||||
- 20331:20331
|
||||
- 20341:20341
|
||||
- 20351:20351
|
||||
node_two:
|
||||
container_name: neo_go_node_two
|
||||
image: env_neo_go_image
|
||||
command: "node --config-path /config --privnet"
|
||||
volumes:
|
||||
- ../config/protocol.privnet.docker.two.yml:/config/protocol.privnet.yml
|
||||
- volume_chain:/chains
|
||||
networks:
|
||||
neo_go_network:
|
||||
ipv4_address: 172.200.0.2
|
||||
ports:
|
||||
- 20332:20332
|
||||
- 20342:20342
|
||||
- 20352:20352
|
||||
node_three:
|
||||
container_name: neo_go_node_three
|
||||
image: env_neo_go_image
|
||||
command: "node --config-path /config --privnet"
|
||||
volumes:
|
||||
- ../config/protocol.privnet.docker.three.yml:/config/protocol.privnet.yml
|
||||
- volume_chain:/chains
|
||||
networks:
|
||||
neo_go_network:
|
||||
ipv4_address: 172.200.0.3
|
||||
ports:
|
||||
- 20333:20333
|
||||
- 20343:20343
|
||||
- 20353:20353
|
||||
node_four:
|
||||
container_name: neo_go_node_four
|
||||
image: env_neo_go_image
|
||||
command: "node --config-path /config --privnet"
|
||||
volumes:
|
||||
- ../config/protocol.privnet.docker.four.yml:/config/protocol.privnet.yml
|
||||
- volume_chain:/chains
|
||||
networks:
|
||||
neo_go_network:
|
||||
ipv4_address: 172.200.0.4
|
||||
ports:
|
||||
- 20334:20334
|
||||
- 20344:20344
|
||||
- 20354:20354
|
||||
depends_on:
|
||||
- node_one
|
||||
- node_two
|
||||
- node_three
|
14
Dockerfile
14
Dockerfile
|
@ -1,5 +1,5 @@
|
|||
# Builder image
|
||||
FROM golang:1.12-alpine3.10 as builder
|
||||
FROM golang:1-alpine as builder
|
||||
|
||||
RUN set -x \
|
||||
&& apk add --no-cache git \
|
||||
|
@ -19,22 +19,18 @@ RUN set -x \
|
|||
&& export GO111MODULE=on \
|
||||
&& export CGO_ENABLED=0 \
|
||||
&& export LDFLAGS="-X ${REPO}/config.Version=${VERSION}" \
|
||||
&& go mod tidy -v \
|
||||
&& go mod vendor \
|
||||
&& go build -v -mod=vendor -ldflags "${LDFLAGS}" -o /go/bin/neo-go ./cli/main.go
|
||||
&& go build -v -mod=vendor -ldflags "${LDFLAGS}" -o /go/bin/neo-go ./cli
|
||||
|
||||
# Executable image
|
||||
FROM alpine:3.10
|
||||
FROM scratch
|
||||
|
||||
ENV NETMODE=testnet
|
||||
ARG VERSION
|
||||
LABEL version=$VERSION
|
||||
|
||||
WORKDIR /
|
||||
|
||||
ENV NETMODE=testnet
|
||||
COPY --from=builder /neo-go/config /config
|
||||
COPY --from=builder /go/bin/neo-go /usr/bin/neo-go
|
||||
COPY --from=builder /neo-go/config /config
|
||||
COPY --from=builder /go/bin/neo-go /usr/bin/neo-go
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
|
||||
ENTRYPOINT ["/usr/bin/neo-go"]
|
||||
|
|
45
Makefile
45
Makefile
|
@ -8,6 +8,8 @@ BINDIR = "/usr/bin"
|
|||
SYSTEMDUNIT_DIR = "/lib/systemd/system"
|
||||
UNITWORKDIR = "/var/lib/neo-go"
|
||||
|
||||
DC_FILE=.docker/docker-compose.yml
|
||||
|
||||
REPO ?= "$(shell go list -m)"
|
||||
VERSION ?= "$(shell git describe --tags 2>/dev/null | sed 's/^v//')"
|
||||
BUILD_FLAGS = "-X $(REPO)/config.Version=$(VERSION)"
|
||||
|
@ -44,7 +46,7 @@ postinst: install
|
|||
&& chown -R neo-go:neo-go $(UNITWORKDIR) $(BINDIR)/neo-go \
|
||||
&& systemctl enable neo-go.service
|
||||
|
||||
image:
|
||||
image: deps
|
||||
@echo "=> Building image"
|
||||
@docker build -t cityofzion/neo-go:latest --build-arg REPO=$(REPO) --build-arg VERSION=$(VERSION) .
|
||||
@docker build -t cityofzion/neo-go:$(VERSION) --build-arg REPO=$(REPO) --build-arg VERSION=$(VERSION) .
|
||||
|
@ -52,12 +54,6 @@ image:
|
|||
check-version:
|
||||
git fetch && (! git rev-list ${VERSION})
|
||||
|
||||
clean-cluster:
|
||||
@echo "=> Removing all containers and chain storage"
|
||||
@rm -rf chains/privnet-docker-one chains/privnet-docker-two chains/privnet-docker-three chains/privnet-docker-four
|
||||
@docker-compose stop
|
||||
@docker-compose rm -f
|
||||
|
||||
deps:
|
||||
@go mod tidy -v
|
||||
@go mod vendor
|
||||
|
@ -77,14 +73,6 @@ push-to-registry:
|
|||
run: build
|
||||
${BINARY} node -config-path ./config -${NETMODE}
|
||||
|
||||
run-cluster: build-linux
|
||||
@echo "=> Starting docker-compose cluster"
|
||||
@echo "=> Building container image"
|
||||
@docker-compose build
|
||||
@docker-compose up -d
|
||||
@echo "=> Tailing logs, exiting this prompt will not stop the cluster"
|
||||
@docker-compose logs -f
|
||||
|
||||
test:
|
||||
@go test ./... -cover
|
||||
|
||||
|
@ -100,3 +88,30 @@ fmt:
|
|||
cover:
|
||||
@go test -v -race ./... -coverprofile=coverage.txt -covermode=atomic
|
||||
@go tool cover -html=coverage.txt -o coverage.html
|
||||
|
||||
# --- Environment ---
|
||||
env_vendor:
|
||||
@echo "=> Update vendor"
|
||||
@go mod tidy
|
||||
@go mod download
|
||||
@go mod vendor
|
||||
|
||||
env_image: env_vendor
|
||||
@echo "=> Building env image"
|
||||
@docker build \
|
||||
-t env_neo_go_image \
|
||||
--build-arg REPO=$(REPO) \
|
||||
--build-arg VERSION=$(VERSION) .
|
||||
|
||||
env_up:
|
||||
@echo "=> Bootup environment"
|
||||
@docker-compose -f $(DC_FILE) up -d node_four
|
||||
|
||||
env_down:
|
||||
@echo "=> Stop and cleanup environment"
|
||||
@docker-compose -f $(DC_FILE) down
|
||||
|
||||
env_restart:
|
||||
@echo "=> Stop and cleanup environment"
|
||||
@docker-compose -f $(DC_FILE) restart
|
||||
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
ProtocolConfiguration:
|
||||
Magic: 56753
|
||||
AddressVersion: 23
|
||||
SecondsPerBlock: 15
|
||||
LowPriorityThreshold: 0.000
|
||||
StandbyValidators:
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList:
|
||||
- node_one:20334
|
||||
- node_two:20335
|
||||
- node_three:20336
|
||||
- 172.20.0.1:20331
|
||||
- 172.20.0.2:20332
|
||||
- 172.20.0.3:20333
|
||||
- 172.20.0.4:20334
|
||||
SystemFee:
|
||||
EnrollmentTransaction: 1000
|
||||
IssueTransaction: 500
|
||||
|
@ -25,7 +28,7 @@ ApplicationConfiguration:
|
|||
Type: "leveldb" #other options: 'inmemory','redis','boltdb'.
|
||||
# DB type options. Uncomment those you need in case you want to switch DB type.
|
||||
LevelDBOptions:
|
||||
DataDirectoryPath: "./chains/privnet"
|
||||
DataDirectoryPath: "/chains/four"
|
||||
# RedisDBOptions:
|
||||
# Addr: "localhost:6379"
|
||||
# Password: ""
|
||||
|
@ -34,7 +37,7 @@ ApplicationConfiguration:
|
|||
# FilePath: "./chains/privnet.bolt"
|
||||
# Uncomment in order to set up custom address for node.
|
||||
# Address: 127.0.0.1
|
||||
NodePort: 20337
|
||||
NodePort: 20334
|
||||
Relay: true
|
||||
DialTimeout: 3
|
||||
ProtoTickInterval: 2
|
||||
|
@ -44,7 +47,10 @@ ApplicationConfiguration:
|
|||
RPC:
|
||||
Enabled: true
|
||||
EnableCORSWorkaround: false
|
||||
Port: 20336
|
||||
Port: 20344
|
||||
Monitoring:
|
||||
Enabled: true
|
||||
Port: 2112
|
||||
Port: 20354
|
||||
UnlockWallet:
|
||||
Path: "6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc"
|
||||
Password: "four"
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
ProtocolConfiguration:
|
||||
Magic: 56753
|
||||
AddressVersion: 23
|
||||
SecondsPerBlock: 15
|
||||
LowPriorityThreshold: 0.000
|
||||
StandbyValidators:
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList: []
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList:
|
||||
- 172.200.0.1:20331
|
||||
- 172.200.0.2:20332
|
||||
- 172.200.0.3:20333
|
||||
- 172.200.0.4:20334
|
||||
SystemFee:
|
||||
EnrollmentTransaction: 1000
|
||||
IssueTransaction: 500
|
||||
|
@ -22,7 +28,7 @@ ApplicationConfiguration:
|
|||
Type: "leveldb" #other options: 'inmemory','redis','boltdb'.
|
||||
# DB type options. Uncomment those you need in case you want to switch DB type.
|
||||
LevelDBOptions:
|
||||
DataDirectoryPath: "./chains/privnet"
|
||||
DataDirectoryPath: "/chains/one"
|
||||
# RedisDBOptions:
|
||||
# Addr: "localhost:6379"
|
||||
# Password: ""
|
||||
|
@ -31,7 +37,7 @@ ApplicationConfiguration:
|
|||
# FilePath: "./chains/privnet.bolt"
|
||||
# Uncomment in order to set up custom address for node.
|
||||
# Address: 127.0.0.1
|
||||
NodePort: 20334
|
||||
NodePort: 20331
|
||||
Relay: true
|
||||
DialTimeout: 3
|
||||
ProtoTickInterval: 2
|
||||
|
@ -41,7 +47,10 @@ ApplicationConfiguration:
|
|||
RPC:
|
||||
Enabled: true
|
||||
EnableCORSWorkaround: false
|
||||
Port: 20333
|
||||
Port: 20341
|
||||
Monitoring:
|
||||
Enabled: true
|
||||
Port: 2112
|
||||
Port: 20351
|
||||
UnlockWallet:
|
||||
Path: "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y"
|
||||
Password: "one"
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
ProtocolConfiguration:
|
||||
Magic: 56753
|
||||
AddressVersion: 23
|
||||
SecondsPerBlock: 15
|
||||
LowPriorityThreshold: 0.000
|
||||
StandbyValidators:
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList: []
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList:
|
||||
- 172.200.0.1:20331
|
||||
- 172.200.0.2:20332
|
||||
- 172.200.0.3:20333
|
||||
- 172.200.0.4:20334
|
||||
SystemFee:
|
||||
EnrollmentTransaction: 1000
|
||||
IssueTransaction: 500
|
||||
|
@ -22,7 +28,7 @@ ApplicationConfiguration:
|
|||
Type: "leveldb" #other options: 'inmemory','redis','boltdb'.
|
||||
# DB type options. Uncomment those you need in case you want to switch DB type.
|
||||
LevelDBOptions:
|
||||
DataDirectoryPath: "./chains/privnet"
|
||||
DataDirectoryPath: "/chains/three"
|
||||
# RedisDBOptions:
|
||||
# Addr: "localhost:6379"
|
||||
# Password: ""
|
||||
|
@ -31,7 +37,7 @@ ApplicationConfiguration:
|
|||
# FilePath: "./chains/privnet.bolt"
|
||||
# Uncomment in order to set up custom address for node.
|
||||
# Address: 127.0.0.1
|
||||
NodePort: 20336
|
||||
NodePort: 20333
|
||||
Relay: true
|
||||
DialTimeout: 3
|
||||
ProtoTickInterval: 2
|
||||
|
@ -41,7 +47,10 @@ ApplicationConfiguration:
|
|||
RPC:
|
||||
Enabled: true
|
||||
EnableCORSWorkaround: false
|
||||
Port: 20335
|
||||
Port: 20343
|
||||
Monitoring:
|
||||
Enabled: true
|
||||
Port: 2112
|
||||
Port: 20353
|
||||
UnlockWallet:
|
||||
Path: "6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh"
|
||||
Password: "three"
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
ProtocolConfiguration:
|
||||
Magic: 56753
|
||||
AddressVersion: 23
|
||||
SecondsPerBlock: 15
|
||||
LowPriorityThreshold: 0.000
|
||||
StandbyValidators:
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList: []
|
||||
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||
- 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e
|
||||
- 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699
|
||||
- 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62
|
||||
SeedList:
|
||||
- 172.200.0.1:20331
|
||||
- 172.200.0.2:20332
|
||||
- 172.200.0.3:20333
|
||||
- 172.200.0.4:20334
|
||||
SystemFee:
|
||||
EnrollmentTransaction: 1000
|
||||
IssueTransaction: 500
|
||||
|
@ -22,7 +28,7 @@ ApplicationConfiguration:
|
|||
Type: "leveldb" #other options: 'inmemory','redis','boltdb'.
|
||||
# DB type options. Uncomment those you need in case you want to switch DB type.
|
||||
LevelDBOptions:
|
||||
DataDirectoryPath: "./chains/privnet"
|
||||
DataDirectoryPath: "/chains/two"
|
||||
# RedisDBOptions:
|
||||
# Addr: "localhost:6379"
|
||||
# Password: ""
|
||||
|
@ -31,7 +37,7 @@ ApplicationConfiguration:
|
|||
# FilePath: "./chains/privnet.bolt"
|
||||
# Uncomment in order to set up custom address for node.
|
||||
# Address: 127.0.0.1
|
||||
NodePort: 20335
|
||||
NodePort: 20332
|
||||
Relay: true
|
||||
DialTimeout: 3
|
||||
ProtoTickInterval: 2
|
||||
|
@ -41,7 +47,10 @@ ApplicationConfiguration:
|
|||
RPC:
|
||||
Enabled: true
|
||||
EnableCORSWorkaround: false
|
||||
Port: 20334
|
||||
Port: 20342
|
||||
Monitoring:
|
||||
Enabled: true
|
||||
Port: 2112
|
||||
Port: 20352
|
||||
UnlockWallet:
|
||||
Path: "6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L"
|
||||
Password: "two"
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
version: '3'
|
||||
services:
|
||||
node_one:
|
||||
build: .
|
||||
volumes:
|
||||
- ./config/protocol.privnet.docker.one.yml:/config/protocol.privnet.yml
|
||||
- ./chains/privnet-docker-one:/chains/privnet
|
||||
ports:
|
||||
- 20334:20334
|
||||
command: "node --config-path /config --privnet"
|
||||
node_two:
|
||||
build: .
|
||||
volumes:
|
||||
- ./config/protocol.privnet.docker.two.yml:/config/protocol.privnet.yml
|
||||
- ./chains/privnet-docker-two:/chains/privnet
|
||||
ports:
|
||||
- 20335:20335
|
||||
command: "node --config-path /config --privnet"
|
||||
node_three:
|
||||
build: .
|
||||
volumes:
|
||||
- ./config/protocol.privnet.docker.three.yml:/config/protocol.privnet.yml
|
||||
- ./chains/privnet-docker-three:/chains/privnet
|
||||
ports:
|
||||
- 20336:20336
|
||||
command: "node --config-path /config --privnet"
|
||||
node_four:
|
||||
build: .
|
||||
volumes:
|
||||
- ./config/protocol.privnet.docker.four.yml:/config/protocol.privnet.yml
|
||||
- ./chains/privnet-docker-four:/chains/privnet
|
||||
ports:
|
||||
- 20337:20337
|
||||
command: "node --config-path /config --privnet"
|
||||
depends_on:
|
||||
- node_one
|
||||
- node_two
|
||||
- node_three
|
|
@ -26,7 +26,7 @@ type PrometheusConfig struct {
|
|||
func NewMetricsService(cfg PrometheusConfig) *Service {
|
||||
return &Service{
|
||||
&http.Server{
|
||||
Addr: cfg.Address + ":" + cfg.Port,
|
||||
Addr: cfg.Address + ":" + cfg.Port,
|
||||
Handler: promhttp.Handler(),
|
||||
}, cfg,
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -68,13 +69,19 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func randomID() uint32 {
|
||||
buf := make([]byte, 4)
|
||||
_, _ = rand.Read(buf)
|
||||
return binary.BigEndian.Uint32(buf)
|
||||
}
|
||||
|
||||
// NewServer returns a new Server, initialized with the given configuration.
|
||||
func NewServer(config ServerConfig, chain core.Blockchainer) *Server {
|
||||
s := &Server{
|
||||
ServerConfig: config,
|
||||
chain: chain,
|
||||
bQueue: newBlockQueue(maxBlockBatch, chain),
|
||||
id: rand.Uint32(),
|
||||
id: randomID(),
|
||||
quit: make(chan struct{}),
|
||||
addrReq: make(chan *Message, config.MinPeers),
|
||||
register: make(chan Peer),
|
||||
|
@ -536,7 +543,3 @@ func (s *Server) RelayDirectly(p Peer, inv *payload.Inventory) {
|
|||
p.WriteMsg(NewMessage(s.Net, CMDInv, inv))
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue