Remove the old SSZ tests [skip ci]
This commit is contained in:
parent
1f352bf440
commit
f14d4c4796
|
@ -1,117 +0,0 @@
|
||||||
# beacon_chain
|
|
||||||
# Copyright (c) 2018-Present Status Research & Development GmbH
|
|
||||||
# Licensed and distributed under either of
|
|
||||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
||||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
||||||
|
|
||||||
import
|
|
||||||
# Standard library
|
|
||||||
os, strutils,
|
|
||||||
# Status libs
|
|
||||||
stew/byteutils,
|
|
||||||
serialization, json_serialization,
|
|
||||||
# Beacon chain internals
|
|
||||||
../../beacon_chain/spec/datatypes
|
|
||||||
|
|
||||||
export # Workaround:
|
|
||||||
# - https://github.com/status-im/nim-serialization/issues/4
|
|
||||||
# - https://github.com/status-im/nim-serialization/issues/5
|
|
||||||
# - https://github.com/nim-lang/Nim/issues/11225
|
|
||||||
serialization.readValue
|
|
||||||
|
|
||||||
# Process legacy EF test format (up to 0.8.1)
|
|
||||||
# -------------------------------------------
|
|
||||||
|
|
||||||
type
|
|
||||||
# TODO: use ref object to avoid allocating
|
|
||||||
# so much on the stack - pending https://github.com/status-im/nim-json-serialization/issues/3
|
|
||||||
|
|
||||||
TestConstants* = object
|
|
||||||
SHARD_COUNT*: int
|
|
||||||
TARGET_COMMITTEE_SIZE*: int
|
|
||||||
MAX_BALANCE_CHURN_QUOTIENT*: int
|
|
||||||
MAX_VALIDATORS_PER_COMMITTEE*: int
|
|
||||||
MIN_PER_EPOCH_CHURN_LIMIT*: int
|
|
||||||
SHUFFLE_ROUND_COUNT*: int
|
|
||||||
DEPOSIT_CONTRACT_TREE_DEPTH*: int
|
|
||||||
MIN_DEPOSIT_AMOUNT*: uint64
|
|
||||||
MAX_EFFECTIVE_BALANCE*: uint64
|
|
||||||
EJECTION_BALANCE*: uint64
|
|
||||||
GENESIS_FORK_VERSION*: uint32
|
|
||||||
GENESIS_SLOT*: Slot
|
|
||||||
GENESIS_EPOCH*: Epoch
|
|
||||||
GENESIS_START_SHARD*: uint64
|
|
||||||
BLS_WITHDRAWAL_PREFIX*: array[1, byte]
|
|
||||||
SECONDS_PER_SLOT*: uint64
|
|
||||||
MIN_ATTESTATION_INCLUSION_DELAY*: uint64
|
|
||||||
SLOTS_PER_EPOCH*: int
|
|
||||||
MIN_SEED_LOOKAHEAD*: int
|
|
||||||
MAX_SEED_LOOKAHEAD*: int
|
|
||||||
EPOCHS_PER_ETH1_VOTING_PERIOD*: uint64
|
|
||||||
SLOTS_PER_HISTORICAL_ROOT*: int
|
|
||||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY*: uint64
|
|
||||||
PERSISTENT_COMMITTEE_PERIOD*: uint64
|
|
||||||
LATEST_RANDAO_MIXES_LENGTH*: int
|
|
||||||
EPOCHS_PER_HISTORICAL_VECTOR*: int
|
|
||||||
EPOCHS_PER_SLASHINGS_VECTOR*: int
|
|
||||||
BASE_REWARD_FACTOR*: uint64
|
|
||||||
WHISTLEBLOWER_REWARD_QUOTIENT*: uint64
|
|
||||||
PROPOSER_REWARD_QUOTIENT*: uint64
|
|
||||||
INACTIVITY_PENALTY_QUOTIENT*: uint64
|
|
||||||
MIN_SLASHING_PENALTY_QUOTIENT*: int
|
|
||||||
MAX_PROPOSER_SLASHINGS*: int
|
|
||||||
MAX_ATTESTER_SLASHINGS*: int
|
|
||||||
MAX_ATTESTATIONS*: int
|
|
||||||
MAX_DEPOSITS*: int
|
|
||||||
MAX_VOLUNTARY_EXITS*: int
|
|
||||||
MAX_TRANSFERS*: int
|
|
||||||
DOMAIN_BEACON_PROPOSER*: DomainType
|
|
||||||
DOMAIN_RANDAO*: DomainType
|
|
||||||
DOMAIN_BEACON_ATTESTER*: DomainType
|
|
||||||
DOMAIN_DEPOSIT*: DomainType
|
|
||||||
DOMAIN_VOLUNTARY_EXIT*: DomainType
|
|
||||||
DOMAIN_TRANSFER*: DomainType
|
|
||||||
|
|
||||||
Tests*[T] = object
|
|
||||||
title*: string
|
|
||||||
summary*: string
|
|
||||||
forks_timeline*: string
|
|
||||||
forks*: seq[string]
|
|
||||||
config*: string
|
|
||||||
runner*: string
|
|
||||||
handler*: string
|
|
||||||
test_cases*: seq[T]
|
|
||||||
|
|
||||||
const
|
|
||||||
FixturesDir* = currentSourcePath.rsplit(DirSep, 1)[0] / "fixtures"
|
|
||||||
JsonTestsDir* = FixturesDir / "json_tests_v0.8.1"
|
|
||||||
|
|
||||||
# #######################
|
|
||||||
# Default init
|
|
||||||
proc default*(T: typedesc): T = discard
|
|
||||||
|
|
||||||
# #######################
|
|
||||||
# JSON deserialization
|
|
||||||
|
|
||||||
proc readValue*[N: static int](r: var JsonReader, a: var array[N, byte]) {.inline.} =
|
|
||||||
# Needed for;
|
|
||||||
# - BLS_WITHDRAWAL_PREFIX
|
|
||||||
# - Fork datatypes
|
|
||||||
# TODO: are all bytes and bytearray serialized as hex?
|
|
||||||
# if so export that to nim-eth
|
|
||||||
hexToByteArray(r.readValue(string), a)
|
|
||||||
|
|
||||||
proc readValue*(r: var JsonReader, a: var seq[byte]) {.inline.} =
|
|
||||||
## Custom deserializer for seq[byte]
|
|
||||||
a = hexToSeqByte(r.readValue(string))
|
|
||||||
|
|
||||||
proc parseTests*(jsonPath: string, T: typedesc): Tests[T] =
|
|
||||||
try:
|
|
||||||
debugEcho " [Debug] Loading file: \"", jsonPath, '\"'
|
|
||||||
result = Json.loadFile(jsonPath, Tests[T])
|
|
||||||
except SerializationError as err:
|
|
||||||
writeStackTrace()
|
|
||||||
stderr.write "Json load issue for file \"", jsonPath, "\"\n"
|
|
||||||
stderr.write err.formatMsg(jsonPath), "\n"
|
|
||||||
quit 1
|
|
|
@ -1,215 +0,0 @@
|
||||||
# beacon_chain
|
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
|
||||||
# Licensed and distributed under either of
|
|
||||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
||||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
||||||
|
|
||||||
import
|
|
||||||
# Standard library
|
|
||||||
os, strutils, strformat, tables, unittest, sequtils, typetraits,
|
|
||||||
# Status libs
|
|
||||||
stew/[byteutils, bitseqs], nimcrypto/hash,
|
|
||||||
serialization/testing/tracing,
|
|
||||||
json_serialization, json_serialization/lexer,
|
|
||||||
# Beacon chain internals
|
|
||||||
../../beacon_chain/ssz,
|
|
||||||
../../beacon_chain/spec/[datatypes, validator, digest, crypto],
|
|
||||||
# Test utilities
|
|
||||||
../testutil,
|
|
||||||
./fixtures_utils_v0_8_1
|
|
||||||
|
|
||||||
const
|
|
||||||
failFast = defined(debug) and false
|
|
||||||
traceOnFailure = defined(debug)
|
|
||||||
|
|
||||||
type
|
|
||||||
SpecObject[T] = ref object of RootObj
|
|
||||||
obj: ref T
|
|
||||||
|
|
||||||
SszStaticTest* = object
|
|
||||||
obj: RootRef
|
|
||||||
objType, objJsonRepr: string
|
|
||||||
expectedBytes: seq[byte]
|
|
||||||
expectedRootHash, expectedSigHash: Eth2Digest
|
|
||||||
hasSigHash: bool
|
|
||||||
line: int
|
|
||||||
|
|
||||||
ReaderProc = proc(r: var JsonReader): RootRef {.cdecl, gcsafe.}
|
|
||||||
TestingProc = proc(file: string, test: SszStaticTest) {.cdecl, gcsafe.}
|
|
||||||
|
|
||||||
SpecTypeVtable = object
|
|
||||||
reader: ReaderProc
|
|
||||||
tester: TestingProc
|
|
||||||
|
|
||||||
let testsDir = JsonTestsDir / "ssz_static" / "core"
|
|
||||||
let minDevTestFile = getTempDir() / "minimal_ssz_test.json"
|
|
||||||
|
|
||||||
var specTypesRTTI = initTable[string, SpecTypeVtable]()
|
|
||||||
|
|
||||||
proc readerImpl[T](r: var JsonReader): RootRef {.cdecl, gcsafe.} =
|
|
||||||
var res = SpecObject[T](obj: new T)
|
|
||||||
res.obj[] = r.readValue(T)
|
|
||||||
RootRef(res)
|
|
||||||
|
|
||||||
# TODO:
|
|
||||||
# Fun fact: With mainnet settings, the BeaconState object
|
|
||||||
# is too large to safely exist as a stack variable. The
|
|
||||||
# `testerImpl` procedure below will trigger a segmentation
|
|
||||||
# fault on its very first line because of it.
|
|
||||||
#
|
|
||||||
# To work-around this issue, this file uses ref objects
|
|
||||||
# to store the loaded test cases, but we must compare them
|
|
||||||
# by value:
|
|
||||||
template valuesAreEqual[T](a, b: ref T): bool =
|
|
||||||
a[] == b[]
|
|
||||||
|
|
||||||
template valuesAreEqual[T](a, b: T): bool =
|
|
||||||
a == b
|
|
||||||
|
|
||||||
template `$`(x: ref auto): string =
|
|
||||||
$(x[])
|
|
||||||
|
|
||||||
proc readSszValueRef*(input: openarray[byte], T: type): ref T =
|
|
||||||
new result
|
|
||||||
result[] = readSszValue(input, T)
|
|
||||||
|
|
||||||
proc testerImpl[T](path: string, sszTest: SszStaticTest) {.cdecl, gcsafe.} =
|
|
||||||
doAssert sszTest.obj != nil
|
|
||||||
var obj = SpecObject[T](sszTest.obj)
|
|
||||||
|
|
||||||
test &"test case on line {sszTest.line}":
|
|
||||||
template execTest(testOpName, testOp, expectedRes) =
|
|
||||||
let ourRes = testOp
|
|
||||||
let success = valuesAreEqual(ourRes, expectedRes)
|
|
||||||
if not success and traceOnFailure:
|
|
||||||
{.gcsafe.}:
|
|
||||||
echo "====== ", testOpName, " failed ", path, ":", sszTest.line
|
|
||||||
echo " our result:"
|
|
||||||
echo " ", ourRes
|
|
||||||
echo " expected result:"
|
|
||||||
echo " ", expectedRes
|
|
||||||
when defined(serialization_tracing):
|
|
||||||
tracingEnabled = true
|
|
||||||
discard testOp
|
|
||||||
tracingEnabled = false
|
|
||||||
echo "======================================================"
|
|
||||||
if failFast: quit 1
|
|
||||||
|
|
||||||
# TODO BEWARE: Passing the boolean expression to `check` directly
|
|
||||||
# will trigger a Nim compilation bomb. This is most likely caused
|
|
||||||
# by a mis-behaving generics instantiations cache when a function
|
|
||||||
# is explicitly instantiated to get its address.
|
|
||||||
# There is a recursive instantiation loop of system's `$` operator.
|
|
||||||
check success
|
|
||||||
|
|
||||||
execTest "serialization",
|
|
||||||
(let ourBytes = SSZ.encode(obj.obj[]); ourBytes),
|
|
||||||
sszTest.expectedBytes
|
|
||||||
|
|
||||||
execTest "root hash check",
|
|
||||||
hash_tree_root(obj.obj[]),
|
|
||||||
sszTest.expectedRootHash
|
|
||||||
|
|
||||||
when hasSigningRoot(T):
|
|
||||||
doAssert sszTest.hasSigHash
|
|
||||||
execTest "sig hash check",
|
|
||||||
signingRoot(obj.obj[]),
|
|
||||||
sszTest.expectedSigHash
|
|
||||||
|
|
||||||
execTest "roundtrip",
|
|
||||||
readSszValueRef(sszTest.expectedBytes, T),
|
|
||||||
obj.obj
|
|
||||||
|
|
||||||
template addSpecTypeRTTI(T: type) =
|
|
||||||
var reader = readerImpl[T]
|
|
||||||
var tester = testerImpl[T]
|
|
||||||
specTypesRTTI.add(T.name, SpecTypeVtable(reader: reader,
|
|
||||||
tester: tester))
|
|
||||||
foreachSpecType(addSpecTypeRTTI)
|
|
||||||
|
|
||||||
proc runTest(path: string, test: SszStaticTest) =
|
|
||||||
if test.objType != "Unsupported":
|
|
||||||
specTypesRTTI[test.objType].tester(path, test)
|
|
||||||
|
|
||||||
proc advanceToClosingBrace(lexer: var JsonLexer, openedBraces = 1) =
|
|
||||||
var closedBraces = 0
|
|
||||||
while closedBraces < openedBraces:
|
|
||||||
while lexer.tok notin {tkCurlyLe, tkCurlyRi}:
|
|
||||||
lexer.next
|
|
||||||
if lexer.tok == tkCurlyLe:
|
|
||||||
dec closedBraces
|
|
||||||
else:
|
|
||||||
inc closedBraces
|
|
||||||
lexer.next
|
|
||||||
|
|
||||||
proc readValue*(r: var JsonReader, result: var SszStaticTest) {.gcsafe.} =
|
|
||||||
r.skipToken tkCurlyLe
|
|
||||||
|
|
||||||
if r.lexer.tok != tkString:
|
|
||||||
r.raiseUnexpectedToken(etString)
|
|
||||||
|
|
||||||
var reader: ReaderProc
|
|
||||||
let key = r.lexer.strVal
|
|
||||||
{.gcsafe.}:
|
|
||||||
if not specTypesRTTI.hasKey(key):
|
|
||||||
result.objType = "Unsupported"
|
|
||||||
r.lexer.advanceToClosingBrace
|
|
||||||
return
|
|
||||||
|
|
||||||
result.objType = key
|
|
||||||
result.line = r.lexer.line
|
|
||||||
reader = specTypesRTTI[key].reader
|
|
||||||
|
|
||||||
r.lexer.next
|
|
||||||
r.skipToken tkColon
|
|
||||||
r.skipToken tkCurlyLe
|
|
||||||
|
|
||||||
while r.lexer.tok == tkString:
|
|
||||||
# TODO: I was hit by a very nasty Nim bug here.
|
|
||||||
# If you use `let` on the next line, the variable will be
|
|
||||||
# aliased to `r.lexer.strVar` instead of being copied.
|
|
||||||
# This will create problems, because the value is modified
|
|
||||||
# on the next line.
|
|
||||||
var field = r.lexer.strVal
|
|
||||||
r.lexer.next
|
|
||||||
r.skipToken tkColon
|
|
||||||
|
|
||||||
case field
|
|
||||||
of "value":
|
|
||||||
result.obj = reader(r)
|
|
||||||
of "serialized":
|
|
||||||
result.expectedBytes = hexToSeqByte r.readValue(string)
|
|
||||||
of "root":
|
|
||||||
result.expectedRootHash = Eth2Digest.fromHex r.readValue(string)
|
|
||||||
of "signing_root":
|
|
||||||
result.expectedSigHash = Eth2Digest.fromHex r.readValue(string)
|
|
||||||
result.hasSigHash = true
|
|
||||||
else:
|
|
||||||
r.raiseUnexpectedField(field, type(result).name)
|
|
||||||
|
|
||||||
if r.lexer.tok == tkComma:
|
|
||||||
r.lexer.next()
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
r.skipToken tkCurlyRi
|
|
||||||
r.skipToken tkCurlyRi
|
|
||||||
|
|
||||||
when failFast:
|
|
||||||
# This will produce faster failures in debug builds
|
|
||||||
{.gcsafe.}: runTest result
|
|
||||||
|
|
||||||
proc executeSuite(path: string) =
|
|
||||||
let sszSuite = path.parseTests SszStaticTest
|
|
||||||
suite &"{path}: {sszSuite.title}":
|
|
||||||
for sszTest in sszSuite.test_cases:
|
|
||||||
runTest path, sszTest
|
|
||||||
|
|
||||||
if fileExists(minDevTestFile):
|
|
||||||
executeSuite minDevTestFile
|
|
||||||
|
|
||||||
for kind, path in walkDir(testsDir):
|
|
||||||
if kind notin {pcFile, pcLinkToFile}: continue
|
|
||||||
if const_preset in path:
|
|
||||||
executeSuite path
|
|
|
@ -1,2 +0,0 @@
|
||||||
-d:"serialization_tracing"
|
|
||||||
-d:"ssz_testing"
|
|
|
@ -1,115 +0,0 @@
|
||||||
# beacon_chain
|
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
|
||||||
# Licensed and distributed under either of
|
|
||||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
||||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
||||||
|
|
||||||
import
|
|
||||||
# Standard library
|
|
||||||
ospaths, unittest, sequtils,
|
|
||||||
# Status libs
|
|
||||||
stint, serialization,
|
|
||||||
# Beacon chain internals
|
|
||||||
../../beacon_chain/ssz,
|
|
||||||
../../beacon_chain/spec/datatypes,
|
|
||||||
# Test utilities
|
|
||||||
../testutil,
|
|
||||||
./fixtures_utils_v0_8_1
|
|
||||||
|
|
||||||
type
|
|
||||||
SSZUint* = object
|
|
||||||
`type`*: string
|
|
||||||
value*: string
|
|
||||||
valid*: bool
|
|
||||||
ssz*: seq[byte]
|
|
||||||
tags*: seq[string]
|
|
||||||
|
|
||||||
const
|
|
||||||
TestsDir = JsonTestsDir / "ssz_generic" / "uint"
|
|
||||||
|
|
||||||
func to(val: string, T: typedesc): T =
|
|
||||||
when T is StUint:
|
|
||||||
val.parse(T)
|
|
||||||
else: # result is unsigned int
|
|
||||||
val.parse(StUint[8 * sizeof(T)]).data
|
|
||||||
|
|
||||||
# TODO strformat for the skipped checks
|
|
||||||
|
|
||||||
template checkSerialization(test: SSZUint, T: typedesc) =
|
|
||||||
if test.valid:
|
|
||||||
let value: T = test.value.to(T)
|
|
||||||
let serialized = SSZ.encode(value)
|
|
||||||
check(serialized == test.ssz)
|
|
||||||
elif test.value != "":
|
|
||||||
# No SSZ encoding -> expected failing serialization test
|
|
||||||
if test.tags.anyIt(it == "uint_underflow"):
|
|
||||||
# TODO: Stint throws RangeError for negative number parsing
|
|
||||||
# https://github.com/status-im/nim-stint/blob/ccf87daac1eef15238ff3d6d2edb138e22180d19/stint/io.nim#L130-L132
|
|
||||||
# TODO: Stint checks with an assert that integer is positive or zero
|
|
||||||
# https://github.com/status-im/nim-stint/blob/ccf87daac1eef15238ff3d6d2edb138e22180d19/stint/io.nim#L35
|
|
||||||
expect RangeError, OverflowError, AssertionError:
|
|
||||||
let value: T = test.value.to(T)
|
|
||||||
else:
|
|
||||||
# TODO tag "uint_overflow" does not throw an exception at the moment
|
|
||||||
echo " [Skipped - Serialization - TODO] tags: ", test.tags
|
|
||||||
else:
|
|
||||||
echo " [Skipped - Serialization - N/A] tags: ", test.tags
|
|
||||||
|
|
||||||
template checkDeserialization(test: SSZUint, T: typedesc) =
|
|
||||||
if test.valid:
|
|
||||||
let deser = SSZ.decode(test.ssz, T)
|
|
||||||
check($deser == test.value)
|
|
||||||
elif test.value == "":
|
|
||||||
# No literal value -> expected failing deserialization test
|
|
||||||
if test.tags.anyIt(it == "wrong_length"):
|
|
||||||
expect IndexError:
|
|
||||||
let deser = SSZ.decode(test.ssz, T)
|
|
||||||
else:
|
|
||||||
echo " [Skipped - Deserialization] tags: ", test.tags
|
|
||||||
else:
|
|
||||||
echo " [Skipped - Deserialization - N/A] tags: ", test.tags
|
|
||||||
|
|
||||||
proc runSSZUintTest(inputTests: Tests[SSZUint]) =
|
|
||||||
# We use Stint string -> uint parser + casting
|
|
||||||
# as it's generic over all unsigned integer size
|
|
||||||
# and not just BiggestUint
|
|
||||||
for test in inputTests.test_cases:
|
|
||||||
if test.`type` == "uint8":
|
|
||||||
test.checkSerialization(uint8)
|
|
||||||
test.checkDeserialization(uint8)
|
|
||||||
elif test.`type` == "uint16":
|
|
||||||
test.checkSerialization(uint16)
|
|
||||||
test.checkDeserialization(uint16)
|
|
||||||
elif test.`type` == "uint32":
|
|
||||||
test.checkSerialization(uint32)
|
|
||||||
test.checkDeserialization(uint32)
|
|
||||||
elif test.`type` == "uint64":
|
|
||||||
test.checkSerialization(uint64)
|
|
||||||
test.checkDeserialization(uint64)
|
|
||||||
# TODO: Stint serialization
|
|
||||||
# elif test.`type` == "uint128":
|
|
||||||
# test.checkSerialization(StUint[128])
|
|
||||||
# elif test.`type` == "uint256":
|
|
||||||
# test.checkSerialization(StUint[256])
|
|
||||||
else:
|
|
||||||
echo " [Skipped] uint size: ", test.`type`
|
|
||||||
|
|
||||||
suite "Official - 0.8.1 - SSZ unsigned integer tests" & preset():
|
|
||||||
block: # "Integers right at or beyond the bounds of the allowed value range"
|
|
||||||
let uintBounds = parseTests(TestsDir / "uint_bounds.json", SSZUint)
|
|
||||||
test uintBounds.summary & preset():
|
|
||||||
runSSZUintTest(uintBounds)
|
|
||||||
|
|
||||||
block: # "Random integers chosen uniformly over the allowed value range"
|
|
||||||
let uintRandom = parseTests(TestsDir / "uint_random.json", SSZUint)
|
|
||||||
test uintRandom.summary & preset():
|
|
||||||
runSSZUintTest(uintRandom)
|
|
||||||
|
|
||||||
# TODO: pending fix for https://github.com/status-im/nim-beacon-chain/issues/280
|
|
||||||
block: # "Serialized integers that are too short or too long"
|
|
||||||
let uintWrongLength = parseTests(TestsDir / "uint_wrong_length.json", SSZUint)
|
|
||||||
test "[Skipped] " & uintWrongLength.summary & preset():
|
|
||||||
# TODO: pending fix for https://github.com/status-im/nim-beacon-chain/issues/280
|
|
||||||
echo " [Skipped] Pending https://github.com/status-im/nim-beacon-chain/issues/280"
|
|
||||||
# runSSZUintTest(uintWrongLength)
|
|
Loading…
Reference in New Issue