diff --git a/Dockerfile.mio b/Dockerfile.mio
new file mode 100644
index 000000000000..6dfcfadb21d9
--- /dev/null
+++ b/Dockerfile.mio
@@ -0,0 +1,88 @@
+# --------------------------------------------
+# WorldLand Mio Testnet Node Dockerfile
+# --------------------------------------------
+# This specialized Dockerfile builds and runs a WorldLand node
+# preconfigured for the Mio testnet network.
+# --------------------------------------------
+
+ARG COMMIT=""
+ARG VERSION=""
+ARG BUILDNUM=""
+
+# --------------------------------------------
+# Stage 1: Build WorldLand binaries in a Go builder container
+# --------------------------------------------
+FROM golang:1.24-alpine AS builder
+
+# Install required build tools
+RUN apk add --no-cache gcc musl-dev linux-headers git
+
+# Set working directory
+WORKDIR /worldland
+
+# Copy Go module files and download dependencies
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Copy the full project source
+COPY . .
+
+# Build the WorldLand binary (statically linked)
+RUN go run build/ci.go install -static ./cmd/worldland
+
+# --------------------------------------------
+# Stage 2: Create a minimal runtime container with the built binary
+# --------------------------------------------
+FROM alpine:latest
+
+# Install runtime dependencies
+RUN apk add --no-cache ca-certificates curl jq
+
+# Create data directory for blockchain data
+RUN mkdir -p /worldland/data
+
+# Copy the compiled worldland binary
+COPY --from=builder /worldland/build/bin/worldland /usr/local/bin/
+
+# Expose standard blockchain ports
+# 8545: HTTP-RPC server
+# 8546: WS-RPC server
+# 30303: P2P network (TCP & UDP)
+EXPOSE 8545 8546 30303 30303/udp
+
+# Set data directory as volume
+VOLUME ["/worldland/data"]
+
+# Default entrypoint runs worldland with Mio testnet flag
+# Users can override CMD to add additional flags
+ENTRYPOINT ["worldland"]
+
+# Default command runs Mio testnet with common settings
+# --mio: Use Mio testnet network
+# --datadir: Store blockchain data in /worldland/data
+# --http: Enable HTTP-RPC server
+# --http.addr: Listen on all interfaces
+# --http.corsdomain: Allow CORS from any origin (adjust for production)
+# --http.vhosts: Allow any virtual host (adjust for production)
+CMD ["--mio", \
+ "--datadir", "/worldland/data", \
+ "--http", \
+ "--http.addr", "0.0.0.0", \
+ "--http.api", "eth,net,web3,txpool", \
+ "--http.corsdomain", "*", \
+ "--http.vhosts", "*"]
+
+# --------------------------------------------
+# Metadata labels for programmatic image tracking
+# --------------------------------------------
+ARG COMMIT=""
+ARG VERSION=""
+ARG BUILDNUM=""
+
+LABEL org.opencontainers.image.title="WorldLand Mio Testnet Node"
+LABEL org.opencontainers.image.description="WorldLand blockchain node for Mio testnet network"
+LABEL org.opencontainers.image.source="https://github.com/cryptoecc/WorldLand"
+LABEL commit="$COMMIT"
+LABEL version="$VERSION"
+LABEL buildnum="$BUILDNUM"
+LABEL network="mio-testnet"
diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go
index 049d07d84346..e1ecc8cf03a9 100644
--- a/cmd/devp2p/nodesetcmd.go
+++ b/cmd/devp2p/nodesetcmd.go
@@ -241,6 +241,8 @@ func ethFilter(args []string) (nodeFilter, error) {
filter = forkid.NewStaticFilter(params.SeoulChainConfig, params.SeoulGenesisHash)
case "gwangju":
filter = forkid.NewStaticFilter(params.GwangjuChainConfig, params.GwangjuGenesisHash)
+ case "mio":
+ filter = forkid.NewStaticFilter(params.MioChainConfig, params.MioGenesisHash)
default:
return nil, fmt.Errorf("unknown network %q", args[0])
}
diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go
index 52492a6be6d2..b6fde361f4af 100644
--- a/cmd/evm/internal/t8ntool/block.go
+++ b/cmd/evm/internal/t8ntool/block.go
@@ -57,6 +57,8 @@ type header struct {
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
Codeword []byte `json:"codeword" rlp:"optional"`
CodeLength uint64 `json:"codelength" rlp:"optional"`
+ VRFProof []byte `json:"vrfProof" rlp:"optional"`
+ VRFPublicKey []byte `json:"vrfPublicKey" rlp:"optional"`
}
type headerMarshaling struct {
@@ -165,6 +167,12 @@ func (i *bbInput) ToBlock() *types.Block {
if header.CodeLength != 0 {
header.CodeLength = i.Header.CodeLength
}
+ if header.VRFProof != nil {
+ header.VRFProof = i.Header.VRFProof
+ }
+ if header.VRFPublicKey != nil {
+ header.VRFPublicKey = i.Header.VRFPublicKey
+ }
return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers)
}
diff --git a/cmd/evm/internal/t8ntool/gen_header.go b/cmd/evm/internal/t8ntool/gen_header.go
index db2c8266a5bd..3e0b360e84ce 100644
--- a/cmd/evm/internal/t8ntool/gen_header.go
+++ b/cmd/evm/internal/t8ntool/gen_header.go
@@ -36,7 +36,8 @@ func (h header) MarshalJSON() ([]byte, error) {
BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"`
Codeword hexutil.Bytes `json:"codeword" rlp:"optional"`
CodeLength math.HexOrDecimal64 `json:"codelength" rlp:"optional"`
-
+ VRFProof hexutil.Bytes `json:"vrfProof" rlp:"optional"`
+ VRFPublicKey hexutil.Bytes `json:"vrfPublicKey" rlp:"optional"`
}
var enc header
enc.ParentHash = h.ParentHash
@@ -57,6 +58,8 @@ func (h header) MarshalJSON() ([]byte, error) {
enc.BaseFee = (*math.HexOrDecimal256)(h.BaseFee)
enc.Codeword = h.Codeword
enc.CodeLength = math.HexOrDecimal64(h.CodeLength)
+ enc.VRFProof = h.VRFProof
+ enc.VRFPublicKey = h.VRFPublicKey
return json.Marshal(&enc)
}
@@ -81,6 +84,8 @@ func (h *header) UnmarshalJSON(input []byte) error {
BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"`
Codeword *hexutil.Bytes `json:"codeword" rlp:"optional"`
CodeLength *math.HexOrDecimal64 `json:"codelength" rlp:"optional"`
+ VRFProof *hexutil.Bytes `json:"vrfProof" rlp:"optional"`
+ VRFPublicKey *hexutil.Bytes `json:"vrfPublicKey" rlp:"optional"`
}
var dec header
if err := json.Unmarshal(input, &dec); err != nil {
@@ -144,5 +149,11 @@ func (h *header) UnmarshalJSON(input []byte) error {
if dec.CodeLength != nil {
h.CodeLength = uint64(*dec.CodeLength)
}
+ if dec.VRFProof != nil {
+ h.VRFProof = *dec.VRFProof
+ }
+ if dec.VRFPublicKey != nil {
+ h.VRFPublicKey = *dec.VRFPublicKey
+ }
return nil
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 40de3a86e0a1..9a81303f1a05 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -162,6 +162,11 @@ var (
Usage: "Gwangju network: Error-Correction Codes Proof-of-Work Test Network",
}
+ MioFlag = &cli.BoolFlag{
+ Name: "mio",
+ Usage: "Mio network: Error-Correction Codes Proof-of-Work Test Network",
+ }
+
// Dev mode
DeveloperFlag = &cli.BoolFlag{
Name: "dev",
@@ -996,6 +1001,7 @@ var (
SepoliaFlag,
KilnFlag,*/
GwangjuFlag,
+ MioFlag,
}
// NetworkFlags is the flag group of all built-in supported networks.
NetworkFlags = append([]cli.Flag{
@@ -1039,6 +1045,9 @@ func MakeDataDir(ctx *cli.Context) string {
if ctx.Bool(GwangjuFlag.Name) {
return filepath.Join(path, "gwangju")
}
+ if ctx.Bool(MioFlag.Name) {
+ return filepath.Join(path, "mio")
+ }
return path
}
Fatalf("Cannot determine default data directory, please set manually (--datadir)")
@@ -1099,7 +1108,11 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls = params.SeoulBootnodes
case ctx.Bool(GwangjuFlag.Name):
urls = params.GwangjuBootnodes
+ case ctx.Bool(MioFlag.Name):
+ urls = params.MioBootnodes
+
}
+
// don't apply defaults if BootstrapNodes is already set
if cfg.BootstrapNodes != nil {
return
@@ -1560,7 +1573,10 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "seoul")
case ctx.Bool(GwangjuFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "gwangju")
+ case ctx.Bool(MioFlag.Name) && cfg.DataDir == node.DefaultDataDir():
+ cfg.DataDir = filepath.Join(node.DefaultDataDir(), "mio")
}
+
}
func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) {
@@ -1751,7 +1767,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// Avoid conflicting network flags
//CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag, KilnFlag, SeoulFlag, GwangjuFlag)
- CheckExclusive(ctx, DeveloperFlag, SeoulFlag, GwangjuFlag)
+ CheckExclusive(ctx, DeveloperFlag, SeoulFlag, GwangjuFlag, MioFlag)
CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 {
@@ -1944,6 +1960,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
}
cfg.Genesis = core.DefaultGwangjuGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.GwangjuGenesisHash)
+
+ case ctx.Bool(MioFlag.Name):
+ if !ctx.IsSet(NetworkIdFlag.Name) {
+ cfg.NetworkId = 10396
+ }
+ cfg.Genesis = core.DefaultMioGenesisBlock()
+ SetDNSDiscoveryDefaults(cfg, params.MioGenesisHash)
+
case ctx.Bool(DeveloperFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 1337
@@ -2199,6 +2223,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
genesis = core.DefaultSeoulGenesisBlock()
case ctx.Bool(GwangjuFlag.Name):
genesis = core.DefaultGwangjuGenesisBlock()
+ case ctx.Bool(MioFlag.Name):
+ genesis = core.DefaultMioGenesisBlock()
case ctx.Bool(DeveloperFlag.Name):
Fatalf("Developer chains are ephemeral")
}
@@ -2230,7 +2256,12 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (*core.BlockChain, ethdb.Data
ethashConfig.PowMode = ethash.ModeFake
}
- engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, &eccpowConfig, nil, false, chainDb)
+ kaijuConfig := ethconfig.Defaults.Kaiju
+ if ctx.Bool(FakePoWFlag.Name) {
+ ethashConfig.PowMode = ethash.ModeFake
+ }
+
+ engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, &eccpowConfig, &kaijuConfig, nil, false, chainDb)
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
}
diff --git a/cmd/worldland/main.go b/cmd/worldland/main.go
index ff0b3da305f3..ae4f50c441a5 100644
--- a/cmd/worldland/main.go
+++ b/cmd/worldland/main.go
@@ -296,6 +296,9 @@ func prepare(ctx *cli.Context) {
case ctx.IsSet(utils.GwangjuFlag.Name):
log.Info("Starting Worldland on Gwangju testnet ...")
+ case ctx.IsSet(utils.MioFlag.Name):
+ log.Info("Starting Worldland on Mio testnet ...")
+
case ctx.IsSet(utils.DeveloperFlag.Name):
log.Info("Starting Worldland in ephemeral dev mode...")
log.Warn(`You are running Worldland in --dev mode. Please note the following:
@@ -313,7 +316,7 @@ func prepare(ctx *cli.Context) {
5. Networking is disabled; there is no listen-address, the maximum number of peers is set
to 0, and discovery is disabled.
`)
-
+
case !ctx.IsSet(utils.NetworkIdFlag.Name):
log.Info("Starting clinet on Worldland Seoul mainnet...")
ctx.Set(utils.SeoulFlag.Name, strconv.FormatBool(true))
@@ -321,13 +324,14 @@ func prepare(ctx *cli.Context) {
// If we're a full node on mainnet without --cache specified, bump default cache allowance
if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
// Make sure we're not on any supported preconfigured testnet either
- if !ctx.IsSet(utils.RopstenFlag.Name) &&
+ if !ctx.IsSet(utils.RopstenFlag.Name) &&
!ctx.IsSet(utils.SepoliaFlag.Name) &&
!ctx.IsSet(utils.RinkebyFlag.Name) &&
!ctx.IsSet(utils.GoerliFlag.Name) &&
!ctx.IsSet(utils.KilnFlag.Name) &&
!ctx.IsSet(utils.SeoulFlag.Name) &&
!ctx.IsSet(utils.GwangjuFlag.Name) &&
+ !ctx.IsSet(utils.MioFlag.Name) &&
!ctx.IsSet(utils.DeveloperFlag.Name) {
// Nope, we're really on mainnet. Bump that cache up!
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
diff --git a/consensus/kaiju/LDPCDecoder.go b/consensus/kaiju/LDPCDecoder.go
new file mode 100644
index 000000000000..f199989667c3
--- /dev/null
+++ b/consensus/kaiju/LDPCDecoder.go
@@ -0,0 +1,210 @@
+package kaiju
+
+import (
+ "encoding/binary"
+ "math"
+
+ "github.com/cryptoecc/WorldLand/core/types"
+ "github.com/cryptoecc/WorldLand/crypto"
+)
+
+//OptimizedDecoding return hashVector, outputWord, LRrtl
+func OptimizedDecoding(parameters Parameters, hashVector []int, H, rowInCol, colInRow [][]int) ([]int, []int, [][]float64) {
+ outputWord := make([]int, parameters.n)
+ LRqtl := make([][]float64, parameters.n)
+ LRrtl := make([][]float64, parameters.n)
+ LRft := make([]float64, parameters.n)
+
+ for i := 0; i < parameters.n; i++ {
+ LRqtl[i] = make([]float64, parameters.m)
+ LRrtl[i] = make([]float64, parameters.m)
+ LRft[i] = math.Log((1-crossErr)/crossErr) * float64((hashVector[i]*2 - 1))
+ }
+ LRpt := make([]float64, parameters.n)
+
+ for ind := 1; ind <= maxIter; ind++ {
+ for t := 0; t < parameters.n; t++ {
+ temp3 := 0.0
+
+ for mp := 0; mp < parameters.wc; mp++ {
+ temp3 = infinityTest(temp3 + LRrtl[t][rowInCol[mp][t]])
+ }
+ for m := 0; m < parameters.wc; m++ {
+ temp4 := temp3
+ temp4 = infinityTest(temp4 - LRrtl[t][rowInCol[m][t]])
+ LRqtl[t][rowInCol[m][t]] = infinityTest(LRft[t] + temp4)
+ }
+ }
+
+ for k := 0; k < parameters.wr; k++ {
+ for l := 0; l < parameters.wr; l++ {
+ temp3 := 0.0
+ sign := 1.0
+ tempSign := 0.0
+ for m := 0; m < parameters.wr; m++ {
+ if m != l {
+ temp3 = temp3 + funcF(math.Abs(LRqtl[colInRow[m][k]][k]))
+ if LRqtl[colInRow[m][k]][k] > 0.0 {
+ tempSign = 1.0
+ } else {
+ tempSign = -1.0
+ }
+ sign = sign * tempSign
+ }
+ }
+ magnitude := funcF(temp3)
+ LRrtl[colInRow[l][k]][k] = infinityTest(sign * magnitude)
+ }
+ }
+
+ for t := 0; t < parameters.n; t++ {
+ LRpt[t] = infinityTest(LRft[t])
+ for k := 0; k < parameters.wc; k++ {
+ LRpt[t] += LRrtl[t][rowInCol[k][t]]
+ LRpt[t] = infinityTest(LRpt[t])
+ }
+
+ /*
+ if LRpt[t] >= 0 {
+ outputWord[t] = 1
+ } else {
+ outputWord[t] = 0
+ }*/
+ }
+ }
+
+ for t := 0; t < parameters.n; t++ {
+ if LRpt[t] >= 0 {
+ outputWord[t] = 1
+ } else {
+ outputWord[t] = 0
+ }
+ }
+
+ return hashVector, outputWord, LRrtl
+}
+
+//OptimizedDecoding return hashVector, outputWord, LRrtl
+func OptimizedDecodingSeoul(parameters Parameters, hashVector []int, H, rowInCol, colInRow [][]int) ([]int, []int, [][]float64) {
+ outputWord := make([]int, parameters.n)
+ LRqtl := make([][]float64, parameters.n)
+ LRrtl := make([][]float64, parameters.n)
+ LRft := make([]float64, parameters.n)
+
+ for i := 0; i < parameters.n; i++ {
+ LRqtl[i] = make([]float64, parameters.m)
+ LRrtl[i] = make([]float64, parameters.m)
+ LRft[i] = math.Log((1-crossErr)/crossErr) * float64((hashVector[i]*2 - 1))
+ }
+ LRpt := make([]float64, parameters.n)
+
+ for ind := 1; ind <= maxIter; ind++ {
+ for t := 0; t < parameters.n; t++ {
+ temp3 := 0.0
+
+ for mp := 0; mp < parameters.wc; mp++ {
+ temp3 = infinityTest(temp3 + LRrtl[t][rowInCol[mp][t]])
+ }
+ for m := 0; m < parameters.wc; m++ {
+ temp4 := temp3
+ temp4 = infinityTest(temp4 - LRrtl[t][rowInCol[m][t]])
+ LRqtl[t][rowInCol[m][t]] = infinityTest(LRft[t] + temp4)
+ }
+ }
+
+ for k := 0; k < parameters.m; k++ {
+ for l := 0; l < parameters.wr; l++ {
+ temp3 := 0.0
+ sign := 1.0
+ tempSign := 0.0
+ for m := 0; m < parameters.wr; m++ {
+ if m != l {
+ temp3 = temp3 + funcF(math.Abs(LRqtl[colInRow[m][k]][k]))
+ if LRqtl[colInRow[m][k]][k] > 0.0 {
+ tempSign = 1.0
+ } else {
+ tempSign = -1.0
+ }
+ sign = sign * tempSign
+ }
+ }
+ magnitude := funcF(temp3)
+ LRrtl[colInRow[l][k]][k] = infinityTest(sign * magnitude)
+ }
+ }
+
+ for t := 0; t < parameters.n; t++ {
+ LRpt[t] = infinityTest(LRft[t])
+ for k := 0; k < parameters.wc; k++ {
+ LRpt[t] += LRrtl[t][rowInCol[k][t]]
+ LRpt[t] = infinityTest(LRpt[t])
+ }
+
+
+ if LRpt[t] >= 0 {
+ outputWord[t] = 1
+ } else {
+ outputWord[t] = 0
+ }
+ }
+ }
+ /*
+ for t := 0; t < parameters.n; t++ {
+ if LRpt[t] >= 0 {
+ outputWord[t] = 1
+ } else {
+ outputWord[t] = 0
+ }
+ }*/
+
+ return hashVector, outputWord, LRrtl
+}
+
+
+//VerifyOptimizedDecoding return bool, hashVector, outputword, digest which are used for validation
+func VerifyOptimizedDecoding(header *types.Header, hash []byte) (bool, []int, []int, []byte) {
+ parameters, _ := setParameters(header)
+ H := generateH(parameters)
+ colInRow, rowInCol := generateQ(parameters, H)
+
+ seed := make([]byte, 40)
+ copy(seed, hash)
+ binary.LittleEndian.PutUint64(seed[32:], header.Nonce.Uint64())
+ seed = crypto.Keccak512(seed)
+
+ hashVector := generateHv(parameters, seed)
+ hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecoding(parameters, hashVector, H, rowInCol, colInRow)
+ //hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecodingSeoul(parameters, hashVector, H, rowInCol, colInRow)
+
+ flag , _ := MakeDecision(header, colInRow, outputWordOfVerification)
+
+ if flag {
+ return true, hashVectorOfVerification, outputWordOfVerification, seed
+ }
+
+ return false, hashVectorOfVerification, outputWordOfVerification, seed
+}
+
+//VerifyOptimizedDecoding return bool, hashVector, outputword, digest which are used for validation
+func VerifyOptimizedDecodingSeoul(header *types.Header, hash []byte) (bool, []int, []int, []byte) {
+ parameters, _ := setParameters_Seoul(header)
+ H := generateH(parameters)
+ colInRow, rowInCol := generateQ(parameters, H)
+
+ seed := make([]byte, 40)
+ copy(seed, hash)
+ binary.LittleEndian.PutUint64(seed[32:], header.Nonce.Uint64())
+ seed = crypto.Keccak512(seed)
+
+ hashVector := generateHv(parameters, seed)
+ //hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecoding(parameters, hashVector, H, rowInCol, colInRow)
+ hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecodingSeoul(parameters, hashVector, H, rowInCol, colInRow)
+
+ flag , _ := MakeDecision_Seoul(header, colInRow, outputWordOfVerification)
+
+ if flag {
+ return true, hashVectorOfVerification, outputWordOfVerification, seed
+ }
+
+ return false, hashVectorOfVerification, outputWordOfVerification, seed
+}
diff --git a/consensus/kaiju/LDPCDecoder_test.go b/consensus/kaiju/LDPCDecoder_test.go
new file mode 100644
index 000000000000..4af0c7bcbfc2
--- /dev/null
+++ b/consensus/kaiju/LDPCDecoder_test.go
@@ -0,0 +1,79 @@
+package kaiju
+
+import (
+ "math/rand"
+ "reflect"
+ "testing"
+
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+func TestNonceDecoding(t *testing.T) {
+ LDPCNonce := generateRandomNonce()
+ EncodedNonce := types.EncodeNonce(LDPCNonce)
+ DecodedNonce := EncodedNonce.Uint64()
+
+ if LDPCNonce == DecodedNonce {
+ t.Logf("LDPCNonce : %v\n", LDPCNonce)
+ t.Logf("Decoded Nonce : %v\n", DecodedNonce)
+ } else {
+ t.Errorf("LDPCNonce : %v\n", LDPCNonce)
+ t.Errorf("Decoded Nonce : %v\n", DecodedNonce)
+ }
+}
+
+func TestGenerateH(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ header := new(types.Header)
+ header.Difficulty = ProbToDifficulty(Table[0].miningProb)
+
+ parameters, _ := setParameters(header)
+
+ H1 := generateH(parameters)
+ H2 := generateH(parameters)
+
+ if !reflect.DeepEqual(H1, H2) {
+ t.Error("Wrong")
+ }
+ }
+}
+
+func TestRandShuffle(t *testing.T) {
+ for attempt := 0; attempt < 100; attempt++ {
+ var hSeed int64
+ var colOrder []int
+
+ for i := 1; i < 4; i++ {
+ colOrder = nil
+ for j := 0; j < 32; j++ {
+ colOrder = append(colOrder, j)
+ }
+
+ rand.Seed(hSeed)
+ rand.Shuffle(len(colOrder), func(i, j int) {
+ colOrder[i], colOrder[j] = colOrder[j], colOrder[i]
+ })
+ hSeed--
+ }
+
+ var hSeed2 int64
+ var colOrder2 []int
+
+ for i := 1; i < 4; i++ {
+ colOrder2 = nil
+ for j := 0; j < 32; j++ {
+ colOrder2 = append(colOrder2, j)
+ }
+
+ rand.Seed(hSeed2)
+ rand.Shuffle(len(colOrder2), func(i, j int) {
+ colOrder2[i], colOrder2[j] = colOrder2[j], colOrder2[i]
+ })
+ hSeed2--
+ }
+
+ if !reflect.DeepEqual(colOrder, colOrder2) {
+ t.Error("Wrong")
+ }
+ }
+}
diff --git a/consensus/kaiju/LDPCDifficulty.go b/consensus/kaiju/LDPCDifficulty.go
new file mode 100644
index 000000000000..81092cb22606
--- /dev/null
+++ b/consensus/kaiju/LDPCDifficulty.go
@@ -0,0 +1,262 @@
+package kaiju
+
+import (
+ "math"
+ "math/big"
+
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+/*
+ https://ethereum.stackexchange.com/questions/5913/how-does-the-ethereum-homestead-difficulty-adjustment-algorithm-work?noredirect=1&lq=1
+ https://github.com/ethereum/EIPs/issues/100
+
+ Ethereum difficulty adjustment
+ algorithm:
+ diff = (parent_diff +
+ (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99))
+ ) + 2^(periodCount - 2)
+
+ LDPC difficulty adjustment
+ algorithm:
+ diff = (parent_diff +
+ (parent_diff / 256 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // BlockGenerationTime), -99)))
+
+ Why 8?
+ This number is sensitivity of blockgeneration time
+ If this number is high, difficulty is not changed much when block generation time is different from goal of block generation time
+ But if this number is low, difficulty is changed much when block generatin time is different from goal of block generation time
+
+*/
+
+// "github.com/cryptoecc/WorldLand/consensus/ethash/consensus.go"
+// Some weird constants to avoid constant memory allocs for them.
+var (
+ MinimumDifficulty = ProbToDifficulty(Table[0].miningProb)
+ BlockGenerationTime = big.NewInt(36) // 36) // 10 ) // 36)
+ Sensitivity = big.NewInt(8)
+ SensitivityAnnapurna = big.NewInt(1024)
+ threshold = big.NewInt(7)
+
+ // BlockGenerationTime for Seoul
+ BlockGenerationTimeSeoul = big.NewInt(10) // 36) // 10 ) // 36)
+ SeoulDifficulty = big.NewInt(1023)
+
+ //initLevel int = 10
+ minLevel int = 10
+ diff_interval = 100
+
+ //count int = -1
+ //init_c int = 2
+)
+
+const (
+ // frontierDurationLimit is for Frontier:
+ // The decision boundary on the blocktime duration used to determine
+ // whether difficulty should go up or down.
+ frontierDurationLimit = 10
+ // minimumDifficulty The minimum that the difficulty may ever be.
+ minimumDifficulty = 131072
+ // expDiffPeriod is the exponential difficulty period
+ expDiffPeriodUint = 100000
+ // difficultyBoundDivisorBitShift is the bound divisor of the difficulty (2048),
+ // This constant is the right-shifts to use for the division.
+ difficultyBoundDivisor = 11
+)
+
+// MakeLDPCDifficultyCalculator calculate difficulty using difficulty table
+func MakeLDPCDifficultyCalculator() func(time uint64, parent *types.Header) *big.Int {
+ return func(time uint64, parent *types.Header) *big.Int {
+ bigTime := new(big.Int).SetUint64(time)
+ bigParentTime := new(big.Int).SetUint64(parent.Time)
+
+ // holds intermediate values to make the algo easier to read & audit
+ x := new(big.Int)
+ y := new(big.Int)
+
+ // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // BlockGenerationTime
+ x.Sub(bigTime, bigParentTime)
+ //fmt.Printf("block_timestamp - parent_timestamp : %v\n", x)
+
+ x.Div(x, BlockGenerationTime)
+ //fmt.Printf("(block_timestamp - parent_timestamp) / BlockGenerationTime : %v\n", x)
+
+ if parent.UncleHash == types.EmptyUncleHash {
+ //fmt.Printf("No uncle\n")
+ x.Sub(big1, x)
+ } else {
+ //fmt.Printf("Uncle block exists")
+ x.Sub(big2, x)
+ }
+ //fmt.Printf("(2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) / BlockGenerationTime : %v\n", x)
+
+ // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99)
+ if x.Cmp(bigMinus99) < 0 {
+ x.Set(bigMinus99)
+ }
+ //fmt.Printf("max(1 - (block_timestamp - parent_timestamp) / BlockGenerationTime, -99) : %v\n", x)
+
+ // parent_diff + (parent_diff / Sensitivity * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // BlockGenerationTime), -99))
+ y.Div(parent.Difficulty, Sensitivity)
+ //fmt.Printf("parent.Difficulty / 8 : %v\n", y)
+
+ x.Mul(y, x)
+ //fmt.Printf("parent.Difficulty / 8 * max(1 - (block_timestamp - parent_timestamp) / BlockGenerationTime, -99) : %v\n", x)
+
+ x.Add(parent.Difficulty, x)
+ //fmt.Printf("parent.Difficulty - parent.Difficulty / 8 * max(1 - (block_timestamp - parent_timestamp) / BlockGenerationTime, -99) : %v\n", x)
+
+ // minimum difficulty can ever be (before exponential factor)
+ if x.Cmp(MinimumDifficulty) < 0 {
+ x.Set(MinimumDifficulty)
+ }
+
+ //fmt.Printf("x : %v, Minimum difficulty : %v\n", x, MinimumDifficulty)
+ return x
+ }
+}
+
+func MakeLDPCDifficultyCalculator_Seoul() func(time uint64, parent *types.Header) *big.Int {
+ return func(time uint64, parent *types.Header) *big.Int {
+ bigTime := new(big.Int).SetUint64(time)
+ bigParentTime := new(big.Int).SetUint64(parent.Time)
+
+ // holds intermediate values to make the algo easier to read & audit
+ x := new(big.Int)
+ y := new(big.Int)
+
+ // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // BlockGenerationTime
+ x.Sub(bigTime, bigParentTime)
+ //fmt.Printf("block_timestamp - parent_timestamp : %v\n", x)
+
+ x.Div(x, BlockGenerationTimeSeoul)
+ //fmt.Printf("(block_timestamp - parent_timestamp) / BlockGenerationTime : %v\n", x)
+
+ if parent.UncleHash == types.EmptyUncleHash {
+ //fmt.Printf("No uncle\n")
+ x.Sub(big1, x)
+ } else {
+ //fmt.Printf("Uncle block exists")
+ x.Sub(big2, x)
+ }
+ //fmt.Printf("(2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) / BlockGenerationTime : %v\n", x)
+
+ // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99)
+ if x.Cmp(bigMinus99) < 0 {
+ x.Set(bigMinus99)
+ }
+ //fmt.Printf("max(1 - (block_timestamp - parent_timestamp) / BlockGenerationTime, -99) : %v\n", x)
+
+ // parent_diff + (parent_diff / Sensitivity * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // BlockGenerationTime), -99))
+ y.Div(parent.Difficulty, Sensitivity)
+ //fmt.Printf("parent.Difficulty / 8 : %v\n", y)
+
+ x.Mul(y, x)
+ //fmt.Printf("parent.Difficulty / 8 * max(1 - (block_timestamp - parent_timestamp) / BlockGenerationTime, -99) : %v\n", x)
+
+ x.Add(parent.Difficulty, x)
+ //fmt.Printf("parent.Difficulty - parent.Difficulty / 8 * max(1 - (block_timestamp - parent_timestamp) / BlockGenerationTime, -99) : %v\n", x)
+
+ // minimum difficulty can ever be (before exponential factor)
+ if x.Cmp(SeoulDifficulty) < 0 {
+ x.Set(SeoulDifficulty)
+ }
+
+ //fmt.Printf("x : %v, Minimum difficulty : %v\n", x, MinimumDifficulty)
+ return x
+ }
+}
+
+func MakeLDPCDifficultyCalculatorAnnapurna() func(time uint64, parent *types.Header) *big.Int {
+ return func(time uint64, parent *types.Header) *big.Int {
+ bigTime := new(big.Int).SetUint64(time)
+ bigParentTime := new(big.Int).SetUint64(parent.Time)
+
+ // holds intermediate values to make the algo easier to read & audit
+ x := new(big.Int)
+ y := new(big.Int)
+
+ // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // BlockGenerationTime
+ x.Sub(bigTime, bigParentTime)
+ //fmt.Printf("block_timestamp - parent_timestamp : %v\n", x)
+
+ x.Div(x, threshold)
+ //fmt.Printf("(block_timestamp - parent_timestamp) // 7 : %v\n", x)
+
+ if parent.UncleHash == types.EmptyUncleHash {
+ //fmt.Printf("No uncle\n")
+ x.Sub(big1, x)
+ } else {
+ //fmt.Printf("Uncle block exists")
+ x.Sub(big2, x)
+ }
+ //fmt.Printf("(2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 7 : %v\n", x)
+
+ // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 7, -99)
+ if x.Cmp(bigMinus99) < 0 {
+ x.Set(bigMinus99)
+ }
+ //fmt.Printf("max(1 - (block_timestamp - parent_timestamp) / 7, -99) : %v\n", x)
+
+ // parent_diff + (parent_diff / Sensitivity * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 7), -99))
+ y.Div(parent.Difficulty, SensitivityAnnapurna)
+ //fmt.Printf("parent.Difficulty / 1024 : %v\n", y)
+
+ x.Mul(y, x)
+ //fmt.Printf("parent.Difficulty / 1024 * max(1 - (block_timestamp - parent_timestamp) // 7, -99) : %v\n", x)
+
+ x.Add(parent.Difficulty, x)
+ //fmt.Printf("parent.Difficulty - parent.Difficulty / 8 * max(1 - (block_timestamp - parent_timestamp) // 7, -99) : %v\n", x)
+
+ // minimum difficulty can ever be (before exponential factor)
+ if x.Cmp(SeoulDifficulty) < 0 {
+ x.Set(SeoulDifficulty)
+ }
+
+ //fmt.Printf("x : %v, Minimum difficulty : %v\n", x, MinimumDifficulty)
+ return x
+ }
+}
+
+// SearchLevel return next level by using currentDifficulty of header
+// Type of Ethereum difficulty is *bit.Int so arg is *big.int
+func SearchLevel(difficulty *big.Int) int {
+ // foo := MakeLDPCDifficultyCalculator()
+ // Next level := SearchNextLevel(foo(currentBlock's time stamp, parentBlock))
+
+ var currentProb = DifficultyToProb(difficulty)
+ var level int
+
+ distance := 1.0
+ for i := range Table {
+ if math.Abs(currentProb-Table[i].miningProb) <= distance {
+ level = Table[i].level
+ distance = math.Abs(currentProb - Table[i].miningProb)
+ } else {
+ break
+ }
+ }
+
+ return level
+}
+
+// SearchLevel return next level by using currentDifficulty of header
+// Type of Ethereum difficulty is *bit.Int so arg is *big.int
+func SearchLevel_Seoul(difficulty *big.Int) int {
+
+ var level int
+
+ difficultyf := new(big.Rat).SetInt(difficulty)
+ level_prob := big.NewRat(29, 20)
+ difficultyf.Quo(difficultyf, new(big.Rat).SetInt(SeoulDifficulty))
+
+ for {
+ difficultyf.Quo(difficultyf, level_prob)
+ level++
+ if difficultyf.Cmp(big.NewRat(1, 1)) < 0 {
+ break
+ }
+ }
+
+ return level
+}
diff --git a/consensus/kaiju/LDPCDifficulty_test.go b/consensus/kaiju/LDPCDifficulty_test.go
new file mode 100644
index 000000000000..a90440a466ad
--- /dev/null
+++ b/consensus/kaiju/LDPCDifficulty_test.go
@@ -0,0 +1,65 @@
+package kaiju
+
+import (
+ "fmt"
+ "math"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+func TestTablePrint(t *testing.T) {
+ for i := range Table {
+ fmt.Printf("level : %v, n : %v, wc : %v, wr : %v, decisionFrom : %v, decisionTo : %v, decisionStep : %v, miningProb : %v \n", Table[i].level, Table[i].n, Table[i].wc, Table[i].wr, Table[i].decisionFrom, Table[i].decisionTo, Table[i].decisionStep, Table[i].miningProb)
+ }
+}
+
+func TestPrintReciprocal(t *testing.T) {
+ for i := range Table {
+ val := 1 / Table[i].miningProb
+ bigInt := FloatToBigInt(val)
+ fmt.Printf("Reciprocal of miningProb : %v \t big Int : %v\n", val, bigInt)
+ }
+}
+
+func TestConversionFunc(t *testing.T) {
+ for i := range Table {
+ difficulty := ProbToDifficulty(Table[i].miningProb)
+ miningProb := DifficultyToProb(difficulty)
+
+ // Consider only integer part.
+ fmt.Printf("Difficulty : %v \t MiningProb : %v\t, probability compare : %v \n", difficulty, miningProb, math.Abs(miningProb-Table[i].miningProb) < 1)
+ }
+}
+
+func TestDifficultyChange(t *testing.T) {
+ var hash []byte
+ currentLevel := 0
+ currentBlock := new(types.Header)
+ // Parent block's timestamp is 0
+ // compare elapse time(timestamp) and parent block's timestamp(0)
+ currentBlock.Difficulty = big.NewInt(0)
+ currentBlock.Time = 0
+ currentBlock.UncleHash = types.EmptyUncleHash
+ for i := 0; i < 5; i++ {
+ fmt.Printf("Current Difficulty : %v\n", currentBlock.Difficulty)
+
+ startTime := time.Now()
+
+ RunOptimizedConcurrencyLDPC(currentBlock, hash)
+ timeStamp := uint64(time.Since(startTime).Seconds())
+ fmt.Printf("Block generation time : %v\n", timeStamp)
+
+ difficultyCalculator := MakeLDPCDifficultyCalculator()
+ nextDifficulty := difficultyCalculator(timeStamp, currentBlock)
+ currentBlock.Difficulty = nextDifficulty
+ nextLevel := SearchLevel(nextDifficulty)
+
+ fmt.Printf("Current prob : %v, Next Level : %v, Next difficulty : %v, Next difficulty from table : %v\n\n", Table[currentLevel].miningProb, Table[nextLevel].level, nextDifficulty, ProbToDifficulty(Table[nextLevel].miningProb))
+ // currentBlock.ParentHash = outputWord conversion from []int to [32]byte
+ currentLevel = nextLevel
+ fmt.Printf("Current Level : %v\n", currentLevel)
+ }
+}
diff --git a/consensus/kaiju/LDPCDifficulty_utils.go b/consensus/kaiju/LDPCDifficulty_utils.go
new file mode 100644
index 000000000000..339bfc91ced7
--- /dev/null
+++ b/consensus/kaiju/LDPCDifficulty_utils.go
@@ -0,0 +1,518 @@
+package kaiju
+
+import (
+ "math/big"
+)
+
+// Table : level, n, wc, wr, decisionFrom, decisionTo, decisionStep, _, miningProb
+/*
+ How to decision
+ 1. The number of ones in outputword % decision_step == 0
+ 2. The number of ones in outputword exists between decision_from to decision_to
+
+ How to change difficulty level
+ - Reciprocal of difficulty is probability
+ - Therefore We can define difficulty is reciprocal of probability
+ - Find close probability
+
+*/
+type difficulty struct {
+ level int
+ n int
+ wc int
+ wr int
+ decisionFrom int
+ decisionTo int
+ decisionStep int
+ _ float32
+ miningProb float64
+}
+
+// FloatToBigInt convert float64 to big integer
+func FloatToBigInt(val float64) *big.Int {
+ // float64 -> bit float -> big int
+ bigFloat := big.NewFloat(val)
+ bigInt := new(big.Int)
+ bigFloat.Int(bigInt)
+
+ return bigInt
+}
+
+// BigIntToFloat convert big int to float64
+func BigIntToFloat(val *big.Int) float64 {
+ // big int -> bit float -> float64
+ bigFloat := new(big.Float).SetInt(val)
+ floatVal, _ := bigFloat.Float64()
+
+ return floatVal
+}
+
+// DifficultyToProb convert difficulty to probability of table
+func DifficultyToProb(difficulty *big.Int) float64 {
+ //big Int -> 1/bigInt -> float64
+ prob := 1 / BigIntToFloat(difficulty)
+ return prob
+}
+
+// ProbToDifficulty convert probability to difficulty of header
+func ProbToDifficulty(miningProb float64) *big.Int {
+ // float64 -> 1/float64 -> big Int
+ difficulty := FloatToBigInt(1 / miningProb)
+ return difficulty
+}
+
+
+func getTable(level int ) difficulty {
+ n := 64 + level * 4
+ return difficulty{level, n, 3, 4, 1/4 * n, 3/4 * n, 1, 0, 0}
+}
+
+
+// Table is difficulty table slice
+var Table = []difficulty{
+ {0, 32, 3, 4, 10, 22, 2, 0.329111, 3.077970e-05},
+ {1, 32, 3, 4, 10, 22, 2, 0.329111, 3.077970e-05},
+ {2, 32, 3, 4, 10, 16, 2, 0.329111, 2.023220e-05},
+ {3, 32, 3, 4, 16, 16, 1, 0.329111, 9.684650e-06},
+ {4, 32, 3, 4, 14, 14, 1, 0.329111, 6.784080e-06},
+ {5, 36, 3, 4, 12, 24, 2, 0.329111, 4.830240e-06},
+ {6, 36, 3, 4, 12, 18, 2, 0.369449, 3.125970e-06},
+ {7, 32, 3, 4, 12, 12, 1, 0.369449, 2.862890e-06},
+ {8, 44, 3, 4, 14, 30, 2, 0.369449, 1.637790e-06},
+ {9, 36, 3, 4, 18, 18, 1, 0.369449, 1.421700e-06},
+ {10, 36, 3, 4, 16, 16, 1, 0.369449, 1.051350e-06},
+ {11, 44, 3, 4, 14, 22, 2, 0.411046, 1.029740e-06},
+ {12, 40, 3, 4, 12, 28, 2, 0.411046, 7.570880e-07},
+ {13, 36, 3, 4, 14, 14, 1, 0.411046, 4.865630e-07},
+ {14, 40, 3, 4, 12, 20, 2, 0.411046, 4.813320e-07},
+ {15, 44, 3, 4, 22, 22, 1, 0.411046, 4.216920e-07},
+ {16, 44, 3, 4, 20, 20, 1, 0.411046, 3.350070e-07},
+ {17, 48, 3, 4, 14, 34, 2, 0.452453, 2.677070e-07},
+ {18, 40, 3, 4, 20, 20, 1, 0.452453, 2.055750e-07},
+ {19, 44, 3, 4, 18, 18, 1, 0.452453, 1.788400e-07},
+ {20, 48, 3, 4, 14, 24, 2, 0.452453, 1.664080e-07},
+ {21, 40, 3, 4, 18, 18, 1, 0.452453, 1.583110e-07},
+ {22, 40, 3, 4, 16, 16, 1, 0.452453, 7.917230e-08},
+ {23, 44, 3, 4, 16, 16, 1, 0.498513, 7.103820e-08},
+ {24, 48, 3, 4, 24, 24, 1, 0.498513, 6.510890e-08},
+ {25, 48, 3, 4, 22, 22, 1, 0.498513, 5.300760e-08},
+ {26, 52, 3, 4, 14, 40, 2, 0.498513, 4.266600e-08},
+ {27, 48, 3, 4, 20, 20, 1, 0.498513, 2.990510e-08},
+ {28, 40, 3, 4, 14, 14, 1, 0.498513, 2.927380e-08},
+ {29, 52, 3, 4, 14, 26, 2, 0.498513, 2.626790e-08},
+ {30, 60, 3, 4, 18, 42, 2, 0.498513, 1.485240e-08},
+ {31, 48, 3, 4, 18, 18, 1, 0.546238, 1.267290e-08},
+ {32, 52, 3, 4, 26, 26, 1, 0.546238, 9.891110e-09},
+ {33, 60, 3, 4, 18, 30, 2, 0.546238, 9.019200e-09},
+ {34, 48, 3, 4, 16, 32, 1, 0.546238, 8.762650e-09},
+ {35, 52, 3, 4, 24, 24, 1, 0.546238, 8.213140e-09},
+ {36, 56, 3, 4, 16, 42, 2, 0.546238, 6.658250e-09},
+ {37, 52, 3, 4, 22, 22, 1, 0.546238, 4.856960e-09},
+ {38, 48, 3, 4, 16, 16, 1, 0.546238, 4.381330e-09},
+ {39, 56, 3, 4, 16, 28, 2, 0.546238, 4.068000e-09},
+ {40, 60, 3, 4, 30, 30, 1, 0.546238, 3.186040e-09},
+ {41, 60, 3, 4, 28, 28, 1, 0.578290, 2.725470e-09},
+ {42, 64, 3, 4, 18, 46, 2, 0.578290, 2.410890e-09},
+ {43, 52, 3, 4, 20, 20, 1, 0.578290, 2.181360e-09},
+ {44, 60, 3, 4, 26, 26, 1, 0.578290, 1.737940e-09},
+ {45, 52, 3, 4, 18, 34, 1, 0.578290, 1.595330e-09},
+ {46, 56, 3, 4, 28, 28, 1, 0.578290, 1.481830e-09},
+ {47, 64, 3, 4, 18, 32, 2, 0.578290, 1.454780e-09},
+ {48, 56, 3, 4, 26, 26, 1, 0.578290, 1.250550e-09},
+ {49, 60, 3, 4, 24, 24, 1, 0.578290, 8.614860e-10},
+ {50, 52, 3, 4, 18, 18, 1, 0.578290, 7.976650e-10},
+ {51, 56, 3, 4, 24, 24, 1, 0.628015, 7.700380e-10},
+ {52, 60, 3, 4, 22, 38, 1, 0.628015, 6.978800e-10},
+ {53, 52, 3, 4, 16, 36, 1, 0.628015, 5.069080e-10},
+ {54, 64, 3, 4, 32, 32, 1, 0.628015, 4.986660e-10},
+ {55, 64, 3, 4, 30, 30, 1, 0.628015, 4.315180e-10},
+ {56, 68, 3, 4, 18, 50, 2, 0.628015, 3.848530e-10},
+ {57, 56, 3, 4, 22, 22, 1, 0.628015, 3.643130e-10},
+ {58, 60, 3, 4, 22, 22, 1, 0.628015, 3.489400e-10},
+ {59, 64, 3, 4, 28, 28, 1, 0.628015, 2.836780e-10},
+ {60, 56, 3, 4, 20, 36, 1, 0.628015, 2.809120e-10},
+ {61, 52, 3, 4, 16, 16, 1, 0.666500, 2.534540e-10},
+ {62, 60, 3, 4, 20, 40, 1, 0.666500, 2.427110e-10},
+ {63, 68, 3, 4, 18, 34, 2, 0.666500, 2.309280e-10},
+ {64, 64, 3, 4, 26, 26, 1, 0.666500, 1.466250e-10},
+ {65, 56, 3, 4, 20, 20, 1, 0.666500, 1.404560e-10},
+ {66, 76, 3, 4, 22, 54, 2, 0.666500, 1.375500e-10},
+ {67, 60, 3, 4, 20, 20, 1, 0.666500, 1.213550e-10},
+ {68, 56, 3, 4, 18, 38, 1, 0.666500, 9.340240e-11},
+ {69, 76, 3, 4, 22, 38, 2, 0.666500, 8.174200e-11},
+ {70, 68, 3, 4, 34, 34, 1, 0.666500, 7.700290e-11},
+ {71, 68, 3, 4, 32, 32, 1, 0.666500, 6.729690e-11},
+ {72, 64, 3, 4, 24, 24, 1, 0.706860, 6.217280e-11},
+ {73, 72, 3, 4, 18, 56, 2, 0.706860, 6.056200e-11},
+ {74, 56, 3, 4, 18, 18, 1, 0.706860, 4.670120e-11},
+ {75, 68, 3, 4, 30, 30, 1, 0.706860, 4.543980e-11},
+ {76, 64, 3, 4, 22, 42, 1, 0.706860, 4.517330e-11},
+ {77, 72, 3, 4, 18, 36, 2, 0.706860, 3.615450e-11},
+ {78, 76, 3, 4, 38, 38, 1, 0.706860, 2.593400e-11},
+ {79, 68, 3, 4, 28, 28, 1, 0.706860, 2.438720e-11},
+ {80, 76, 3, 4, 36, 36, 1, 0.706860, 2.303460e-11},
+ {81, 64, 3, 4, 22, 22, 1, 0.706860, 2.258660e-11},
+ {82, 80, 3, 4, 22, 58, 2, 0.706860, 2.229400e-11},
+ {83, 76, 3, 4, 34, 34, 1, 0.706860, 1.626350e-11},
+ {84, 64, 3, 4, 20, 40, 1, 0.706860, 1.465310e-11},
+ {85, 80, 3, 4, 22, 40, 2, 0.763542, 1.319160e-11},
+ {86, 72, 3, 4, 36, 36, 1, 0.763542, 1.174900e-11},
+ {87, 68, 3, 4, 26, 26, 1, 0.763542, 1.078820e-11},
+ {88, 72, 3, 4, 34, 34, 1, 0.763542, 1.035690e-11},
+ {89, 76, 3, 4, 32, 32, 1, 0.763542, 9.311370e-12},
+ {90, 68, 3, 4, 24, 44, 1, 0.763542, 8.173020e-12},
+ {91, 64, 3, 4, 20, 20, 1, 0.763542, 7.326570e-12},
+ {92, 72, 3, 4, 32, 32, 1, 0.763542, 7.160350e-12},
+ {93, 76, 3, 4, 30, 30, 1, 0.763542, 4.440960e-12},
+ {94, 80, 3, 4, 40, 40, 1, 0.763542, 4.089220e-12},
+ {95, 68, 3, 4, 24, 24, 1, 0.763542, 4.086510e-12},
+ {96, 72, 3, 4, 30, 30, 1, 0.763542, 3.975570e-12},
+ {97, 80, 3, 4, 38, 38, 1, 0.763542, 3.656430e-12},
+ {98, 76, 3, 4, 28, 48, 1, 0.763542, 3.634830e-12},
+ {99, 84, 3, 4, 22, 62, 2, 0.763542, 3.566880e-12},
+ {100, 68, 3, 4, 22, 46, 1, 0.783762, 2.750600e-12},
+ {101, 80, 3, 4, 36, 36, 1, 0.783762, 2.630600e-12},
+ {102, 84, 3, 4, 22, 42, 2, 0.783762, 2.102180e-12},
+ {103, 72, 3, 4, 28, 28, 1, 0.783762, 1.828850e-12},
+ {104, 76, 3, 4, 28, 28, 1, 0.783762, 1.817420e-12},
+ {105, 80, 3, 4, 34, 34, 1, 0.783762, 1.548670e-12},
+ {106, 72, 3, 4, 26, 46, 1, 0.783762, 1.441670e-12},
+ {107, 68, 3, 4, 22, 22, 1, 0.783762, 1.375300e-12},
+ {108, 76, 3, 4, 26, 50, 1, 0.783762, 1.314800e-12},
+ {109, 92, 3, 4, 24, 68, 2, 0.783762, 1.296220e-12},
+ {110, 68, 3, 4, 20, 48, 1, 0.783762, 8.516070e-13},
+ {111, 80, 3, 4, 32, 32, 1, 0.783762, 7.636740e-13},
+ {112, 92, 3, 4, 24, 46, 2, 0.783762, 7.585130e-13},
+ {113, 72, 3, 4, 26, 26, 1, 0.824961, 7.208340e-13},
+ {114, 76, 3, 4, 26, 26, 1, 0.824961, 6.573980e-13},
+ {115, 80, 3, 4, 30, 50, 1, 0.824961, 6.475910e-13},
+ {116, 84, 3, 4, 42, 42, 1, 0.824961, 6.374900e-13},
+ {117, 84, 3, 4, 40, 40, 1, 0.824961, 5.734350e-13},
+ {118, 88, 3, 4, 22, 66, 2, 0.824961, 5.640630e-13},
+ {119, 72, 3, 4, 24, 48, 1, 0.824961, 5.032200e-13},
+ {120, 76, 3, 4, 24, 52, 1, 0.824961, 4.325430e-13},
+ {121, 68, 3, 4, 20, 20, 1, 0.824961, 4.258030e-13},
+ {122, 84, 3, 4, 38, 38, 1, 0.824961, 4.195890e-13},
+ {123, 88, 3, 4, 22, 44, 2, 0.824961, 3.312130e-13},
+ {124, 80, 3, 4, 30, 30, 1, 0.824961, 3.237950e-13},
+ {125, 84, 3, 4, 36, 36, 1, 0.824961, 2.533670e-13},
+ {126, 72, 3, 4, 24, 24, 1, 0.824961, 2.516100e-13},
+ {127, 80, 3, 4, 28, 52, 1, 0.824961, 2.424700e-13},
+ {128, 92, 3, 4, 46, 46, 1, 0.865704, 2.208090e-13},
+ {129, 76, 3, 4, 24, 24, 1, 0.865704, 2.162710e-13},
+ {130, 96, 3, 4, 26, 72, 2, 0.865704, 2.099840e-13},
+ {131, 92, 3, 4, 44, 44, 1, 0.865704, 2.006580e-13},
+ {132, 72, 3, 4, 22, 50, 1, 0.865704, 1.605310e-13},
+ {133, 92, 3, 4, 42, 42, 1, 0.865704, 1.511670e-13},
+ {134, 84, 3, 4, 34, 34, 1, 0.865704, 1.288510e-13},
+ {135, 96, 3, 4, 26, 48, 2, 0.865704, 1.224810e-13},
+ {136, 80, 3, 4, 28, 28, 1, 0.865704, 1.212350e-13},
+ {137, 88, 3, 4, 44, 44, 1, 0.865704, 9.836240e-14},
+ {138, 92, 3, 4, 40, 40, 1, 0.865704, 9.542830e-14},
+ {139, 88, 3, 4, 42, 42, 1, 0.865704, 8.895450e-14},
+ {140, 80, 3, 4, 26, 54, 1, 0.865704, 8.227740e-14},
+ {141, 72, 3, 4, 22, 22, 1, 0.865704, 8.026550e-14},
+ {142, 88, 3, 4, 40, 40, 1, 0.865704, 6.609120e-14},
+ {143, 84, 3, 4, 32, 32, 1, 0.865704, 5.648410e-14},
+ {144, 92, 3, 4, 38, 38, 1, 0.908949, 5.127400e-14},
+ {145, 72, 3, 4, 20, 52, 1, 0.908949, 4.822030e-14},
+ {146, 84, 3, 4, 30, 54, 1, 0.908949, 4.372420e-14},
+ {147, 80, 3, 4, 26, 26, 1, 0.908949, 4.113870e-14},
+ {148, 88, 3, 4, 38, 38, 1, 0.908949, 4.084490e-14},
+ {149, 96, 3, 4, 48, 48, 1, 0.908949, 3.497970e-14},
+ {150, 100, 3, 4, 26, 76, 2, 0.908949, 3.365420e-14},
+ {151, 96, 3, 4, 46, 46, 1, 0.908949, 3.192740e-14},
+ {152, 80, 3, 4, 24, 56, 1, 0.908949, 2.593890e-14},
+ {153, 96, 3, 4, 44, 44, 1, 0.908949, 2.435890e-14},
+ {154, 72, 3, 4, 20, 20, 1, 0.908949, 2.411020e-14},
+ {155, 92, 3, 4, 36, 36, 1, 0.908949, 2.388460e-14},
+ {156, 84, 3, 4, 30, 30, 1, 0.908949, 2.186210e-14},
+ {157, 88, 3, 4, 36, 36, 1, 0.908949, 2.137330e-14},
+ {158, 92, 3, 4, 34, 58, 1, 0.908949, 1.967320e-14},
+ {159, 100, 3, 4, 26, 50, 2, 0.908949, 1.957080e-14},
+ {160, 96, 3, 4, 42, 42, 1, 0.908949, 1.568040e-14},
+ {161, 84, 3, 4, 28, 56, 1, 0.908949, 1.529960e-14},
+ {162, 80, 3, 4, 24, 24, 1, 0.954202, 1.296950e-14},
+ {163, 108, 3, 4, 28, 82, 2, 0.954202, 1.237200e-14},
+ {164, 92, 3, 4, 34, 34, 1, 0.954202, 9.836600e-15},
+ {165, 88, 3, 4, 34, 34, 1, 0.954202, 9.667440e-15},
+ {166, 96, 3, 4, 40, 40, 1, 0.954202, 8.634600e-15},
+ {167, 88, 3, 4, 32, 56, 1, 0.954202, 7.725050e-15},
+ {168, 84, 3, 4, 28, 28, 1, 0.954202, 7.649800e-15},
+ {169, 92, 3, 4, 32, 60, 1, 0.954202, 7.305750e-15},
+ {170, 108, 3, 4, 28, 54, 2, 0.954202, 7.154920e-15},
+ {171, 100, 3, 4, 50, 50, 1, 0.954202, 5.487490e-15},
+ {172, 104, 3, 4, 26, 78, 2, 0.954202, 5.340690e-15},
+ {173, 100, 3, 4, 48, 48, 1, 0.954202, 5.028760e-15},
+ {174, 84, 3, 4, 26, 58, 1, 0.954202, 4.951260e-15},
+ {175, 96, 3, 4, 38, 38, 1, 0.954202, 4.134930e-15},
+ {176, 100, 3, 4, 46, 46, 1, 0.954202, 3.881360e-15},
+ {177, 88, 3, 4, 32, 32, 1, 0.954202, 3.862530e-15},
+ {178, 92, 3, 4, 32, 32, 1, 0.954202, 3.652870e-15},
+ {179, 96, 3, 4, 36, 60, 1, 0.954202, 3.505650e-15},
+ {180, 104, 3, 4, 26, 52, 2, 0.993877, 3.096920e-15},
+ {181, 88, 3, 4, 30, 58, 1, 0.993877, 2.785770e-15},
+ {182, 100, 3, 4, 44, 44, 1, 0.993877, 2.543880e-15},
+ {183, 92, 3, 4, 30, 62, 1, 0.993877, 2.493880e-15},
+ {184, 84, 3, 4, 26, 26, 1, 0.993877, 2.475630e-15},
+ {185, 112, 3, 4, 28, 86, 2, 0.993877, 2.003890e-15},
+ {186, 108, 3, 4, 54, 54, 1, 0.993877, 1.937830e-15},
+ {187, 108, 3, 4, 52, 52, 1, 0.993877, 1.788370e-15},
+ {188, 96, 3, 4, 36, 36, 1, 0.993877, 1.752820e-15},
+ {189, 84, 3, 4, 24, 60, 1, 0.993877, 1.514630e-15},
+ {190, 100, 3, 4, 42, 42, 1, 0.993877, 1.433180e-15},
+ {191, 108, 3, 4, 50, 50, 1, 0.993877, 1.408830e-15},
+ {192, 88, 3, 4, 30, 30, 1, 0.993877, 1.392880e-15},
+ {193, 96, 3, 4, 34, 62, 1, 0.993877, 1.339400e-15},
+ {194, 92, 3, 4, 30, 30, 1, 0.993877, 1.246940e-15},
+ {195, 112, 3, 4, 28, 56, 2, 0.993877, 1.155930e-15},
+ {196, 108, 3, 4, 48, 48, 1, 0.993877, 9.534230e-16},
+ {197, 88, 3, 4, 28, 60, 1, 0.993877, 9.258750e-16},
+ {198, 104, 3, 4, 52, 52, 1, 1.035782, 8.531480e-16},
+ {199, 92, 3, 4, 28, 64, 1, 1.035782, 7.972240e-16},
+ {200, 104, 3, 4, 50, 50, 1, 1.035782, 7.847010e-16},
+ {201, 84, 3, 4, 24, 24, 1, 1.035782, 7.573130e-16},
+ {202, 100, 3, 4, 40, 40, 1, 1.035782, 7.043820e-16},
+ {203, 96, 3, 4, 34, 34, 1, 1.035782, 6.696990e-16},
+ {204, 100, 3, 4, 38, 62, 1, 1.035782, 6.138180e-16},
+ {205, 104, 3, 4, 48, 48, 1, 1.035782, 6.121340e-16},
+ {206, 108, 3, 4, 46, 46, 1, 1.035782, 5.596910e-16},
+ {207, 96, 3, 4, 32, 64, 1, 1.035782, 4.694950e-16},
+ {208, 88, 3, 4, 28, 28, 1, 1.035782, 4.629380e-16},
+ {209, 104, 3, 4, 46, 46, 1, 1.035782, 4.079260e-16},
+ {210, 92, 3, 4, 28, 28, 1, 1.035782, 3.986120e-16},
+ {211, 116, 3, 4, 30, 86, 2, 1.035782, 3.215820e-16},
+ {212, 112, 3, 4, 56, 56, 1, 1.035782, 3.079780e-16},
+ {213, 100, 3, 4, 38, 38, 1, 1.035782, 3.069090e-16},
+ {214, 88, 3, 4, 26, 62, 1, 1.035782, 2.893730e-16},
+ {215, 108, 3, 4, 44, 44, 1, 1.035782, 2.884350e-16},
+ {216, 112, 3, 4, 54, 54, 1, 1.035782, 2.851100e-16},
+ {217, 92, 3, 4, 26, 66, 1, 1.035782, 2.429760e-16},
+ {218, 100, 3, 4, 36, 64, 1, 1.083752, 2.410500e-16},
+ {219, 104, 3, 4, 44, 44, 1, 1.083752, 2.347600e-16},
+ {220, 96, 3, 4, 32, 32, 1, 1.083752, 2.347480e-16},
+ {221, 112, 3, 4, 52, 52, 1, 1.083752, 2.266460e-16},
+ {222, 116, 3, 4, 30, 58, 2, 1.083752, 1.850560e-16},
+ {223, 112, 3, 4, 50, 50, 1, 1.083752, 1.555940e-16},
+ {224, 96, 3, 4, 30, 66, 1, 1.083752, 1.536060e-16},
+ {225, 88, 3, 4, 26, 26, 1, 1.083752, 1.446860e-16},
+ {226, 108, 3, 4, 42, 42, 1, 1.083752, 1.322410e-16},
+ {227, 92, 3, 4, 26, 26, 1, 1.083752, 1.214880e-16},
+ {228, 100, 3, 4, 36, 36, 1, 1.083752, 1.205250e-16},
+ {229, 124, 3, 4, 32, 94, 2, 1.083752, 1.192380e-16},
+ {230, 104, 3, 4, 42, 42, 1, 1.083752, 1.182330e-16},
+ {231, 108, 3, 4, 40, 68, 1, 1.083752, 1.093900e-16},
+ {232, 112, 3, 4, 48, 48, 1, 1.083752, 9.304980e-17},
+ {233, 100, 3, 4, 34, 66, 1, 1.083752, 8.672750e-17},
+ {234, 88, 3, 4, 24, 64, 1, 1.083752, 8.671340e-17},
+ {235, 96, 3, 4, 30, 30, 1, 1.083752, 7.680300e-17},
+ {236, 124, 3, 4, 32, 62, 2, 1.083752, 6.831000e-17},
+ {237, 108, 3, 4, 40, 40, 1, 1.083752, 5.469510e-17},
+ {238, 104, 3, 4, 40, 40, 1, 1.083752, 5.287900e-17},
+ {239, 120, 3, 4, 30, 90, 2, 1.122176, 5.116510e-17},
+ {240, 112, 3, 4, 46, 46, 1, 1.122176, 4.900210e-17},
+ {241, 116, 3, 4, 58, 58, 1, 1.122176, 4.853020e-17},
+ {242, 96, 3, 4, 28, 68, 1, 1.122176, 4.769400e-17},
+ {243, 116, 3, 4, 56, 56, 1, 1.122176, 4.505610e-17},
+ {244, 100, 3, 4, 34, 34, 1, 1.122176, 4.336370e-17},
+ {245, 88, 3, 4, 24, 24, 1, 1.122176, 4.335670e-17},
+ {246, 104, 3, 4, 38, 66, 1, 1.122176, 4.264440e-17},
+ {247, 108, 3, 4, 38, 70, 1, 1.122176, 4.139190e-17},
+ {248, 116, 3, 4, 54, 54, 1, 1.122176, 3.611940e-17},
+ {249, 120, 3, 4, 30, 60, 2, 1.122176, 2.937590e-17},
+ {250, 100, 3, 4, 32, 68, 1, 1.122176, 2.904870e-17},
+ {251, 116, 3, 4, 52, 52, 1, 1.122176, 2.512890e-17},
+ {252, 96, 3, 4, 28, 28, 1, 1.122176, 2.384700e-17},
+ {253, 112, 3, 4, 44, 44, 1, 1.122176, 2.300220e-17},
+ {254, 104, 3, 4, 38, 38, 1, 1.122176, 2.132220e-17},
+ {255, 108, 3, 4, 38, 38, 1, 1.122176, 2.069600e-17},
+ {256, 112, 3, 4, 42, 70, 1, 1.122176, 1.949710e-17},
+ {257, 128, 3, 4, 32, 98, 2, 1.122176, 1.931040e-17},
+ {258, 124, 3, 4, 62, 62, 1, 1.122176, 1.738220e-17},
+ {259, 124, 3, 4, 60, 60, 1, 1.122176, 1.622110e-17},
+ {260, 104, 3, 4, 36, 68, 1, 1.165058, 1.573970e-17},
+ {261, 116, 3, 4, 50, 50, 1, 1.165058, 1.529120e-17},
+ {262, 108, 3, 4, 36, 72, 1, 1.165058, 1.452810e-17},
+ {263, 100, 3, 4, 32, 32, 1, 1.165058, 1.452430e-17},
+ {264, 124, 3, 4, 58, 58, 1, 1.165058, 1.320160e-17},
+ {265, 128, 3, 4, 32, 64, 2, 1.165058, 1.103980e-17},
+ {266, 112, 3, 4, 42, 42, 1, 1.165058, 9.748530e-18},
+ {267, 124, 3, 4, 56, 56, 1, 1.165058, 9.408340e-18},
+ {268, 100, 3, 4, 30, 70, 1, 1.165058, 9.198900e-18},
+ {269, 116, 3, 4, 48, 48, 1, 1.165058, 8.218710e-18},
+ {270, 104, 3, 4, 36, 36, 1, 1.165058, 7.869870e-18},
+ {271, 120, 3, 4, 60, 60, 1, 1.165058, 7.586620e-18},
+ {272, 112, 3, 4, 40, 72, 1, 1.165058, 7.557840e-18},
+ {273, 108, 3, 4, 36, 36, 1, 1.165058, 7.264050e-18},
+ {274, 120, 3, 4, 58, 58, 1, 1.165058, 7.062330e-18},
+ {275, 124, 3, 4, 54, 54, 1, 1.165058, 5.908890e-18},
+ {276, 120, 3, 4, 56, 56, 1, 1.165058, 5.705970e-18},
+ {277, 104, 3, 4, 34, 70, 1, 1.165058, 5.397190e-18},
+ {278, 108, 3, 4, 34, 74, 1, 1.165058, 4.794130e-18},
+ {279, 100, 3, 4, 30, 30, 1, 1.165058, 4.599450e-18},
+ {280, 120, 3, 4, 54, 54, 1, 1.165058, 4.019430e-18},
+ {281, 116, 3, 4, 46, 46, 1, 1.165058, 3.945320e-18},
+ {282, 112, 3, 4, 40, 40, 1, 1.165058, 3.778920e-18},
+ {283, 116, 3, 4, 44, 72, 1, 1.231412, 3.423190e-18},
+ {284, 124, 3, 4, 52, 52, 1, 1.231412, 3.297090e-18},
+ {285, 100, 3, 4, 28, 72, 1, 1.231412, 2.795780e-18},
+ {286, 128, 3, 4, 64, 64, 1, 1.231412, 2.769110e-18},
+ {287, 112, 3, 4, 38, 74, 1, 1.231412, 2.714430e-18},
+ {288, 104, 3, 4, 34, 34, 1, 1.231412, 2.698600e-18},
+ {289, 128, 3, 4, 62, 62, 1, 1.231412, 2.590140e-18},
+ {290, 120, 3, 4, 52, 52, 1, 1.231412, 2.486040e-18},
+ {291, 108, 3, 4, 34, 34, 1, 1.231412, 2.397060e-18},
+ {292, 128, 3, 4, 60, 60, 1, 1.231412, 2.122380e-18},
+ {293, 104, 3, 4, 32, 72, 1, 1.231412, 1.744360e-18},
+ {294, 116, 3, 4, 44, 44, 1, 1.231412, 1.711600e-18},
+ {295, 124, 3, 4, 50, 50, 1, 1.231412, 1.649820e-18},
+ {296, 128, 3, 4, 58, 58, 1, 1.231412, 1.529130e-18},
+ {297, 108, 3, 4, 32, 76, 1, 1.231412, 1.506960e-18},
+ {298, 100, 3, 4, 28, 28, 1, 1.231412, 1.397890e-18},
+ {299, 120, 3, 4, 50, 50, 1, 1.231412, 1.362180e-18},
+ {300, 116, 3, 4, 42, 74, 1, 1.231412, 1.358390e-18},
+ {301, 112, 3, 4, 38, 38, 1, 1.231412, 1.357210e-18},
+ {302, 128, 3, 4, 56, 56, 1, 1.231412, 9.742990e-19},
+ {303, 112, 3, 4, 36, 76, 1, 1.231412, 9.147070e-19},
+ {304, 104, 3, 4, 32, 32, 1, 1.231412, 8.721800e-19},
+ {305, 108, 3, 4, 32, 32, 1, 1.231412, 7.534800e-19},
+ {306, 124, 3, 4, 48, 48, 1, 1.273354, 7.478050e-19},
+ {307, 116, 3, 4, 42, 42, 1, 1.273354, 6.791960e-19},
+ {308, 120, 3, 4, 48, 48, 1, 1.273354, 6.679650e-19},
+ {309, 124, 3, 4, 46, 78, 1, 1.273354, 6.204930e-19},
+ {310, 120, 3, 4, 46, 74, 1, 1.273354, 5.926870e-19},
+ {311, 128, 3, 4, 54, 54, 1, 1.273354, 5.530780e-19},
+ {312, 104, 3, 4, 30, 74, 1, 1.273354, 5.388680e-19},
+ {313, 116, 3, 4, 40, 76, 1, 1.273354, 4.990110e-19},
+ {314, 112, 3, 4, 36, 36, 1, 1.273354, 4.573530e-19},
+ {315, 108, 3, 4, 30, 78, 1, 1.273354, 4.570100e-19},
+ {316, 124, 3, 4, 46, 46, 1, 1.273354, 3.102460e-19},
+ {317, 120, 3, 4, 46, 46, 1, 1.273354, 2.963440e-19},
+ {318, 112, 3, 4, 34, 78, 1, 1.273354, 2.927770e-19},
+ {319, 128, 3, 4, 52, 52, 1, 1.273354, 2.821290e-19},
+ {320, 104, 3, 4, 30, 30, 1, 1.273354, 2.694340e-19},
+ {321, 116, 3, 4, 40, 40, 1, 1.273354, 2.495060e-19},
+ {322, 120, 3, 4, 44, 76, 1, 1.273354, 2.405750e-19},
+ {323, 124, 3, 4, 44, 80, 1, 1.273354, 2.381080e-19},
+ {324, 108, 3, 4, 30, 30, 1, 1.273354, 2.285050e-19},
+ {325, 116, 3, 4, 38, 78, 1, 1.273354, 1.717170e-19},
+ {326, 104, 3, 4, 28, 76, 1, 1.273354, 1.613020e-19},
+ {327, 112, 3, 4, 34, 34, 1, 1.273354, 1.463890e-19},
+ {328, 128, 3, 4, 50, 50, 1, 1.273354, 1.305320e-19},
+ {329, 120, 3, 4, 44, 44, 1, 1.273354, 1.202870e-19},
+ {330, 124, 3, 4, 44, 44, 1, 1.273354, 1.190540e-19},
+ {331, 128, 3, 4, 48, 80, 1, 1.307736, 1.106170e-19},
+ {332, 120, 3, 4, 42, 78, 1, 1.307736, 9.035000e-20},
+ {333, 112, 3, 4, 32, 80, 1, 1.307736, 9.008150e-20},
+ {334, 116, 3, 4, 38, 38, 1, 1.307736, 8.585840e-20},
+ {335, 124, 3, 4, 42, 82, 1, 1.307736, 8.539640e-20},
+ {336, 104, 3, 4, 28, 28, 1, 1.307736, 8.065090e-20},
+ {337, 116, 3, 4, 36, 80, 1, 1.307736, 5.599310e-20},
+ {338, 128, 3, 4, 48, 48, 1, 1.307736, 5.530870e-20},
+ {339, 120, 3, 4, 42, 42, 1, 1.307736, 4.517500e-20},
+ {340, 112, 3, 4, 32, 32, 1, 1.307736, 4.504080e-20},
+ {341, 128, 3, 4, 46, 82, 1, 1.307736, 4.334810e-20},
+ {342, 124, 3, 4, 42, 42, 1, 1.307736, 4.269820e-20},
+ {343, 120, 3, 4, 40, 80, 1, 1.307736, 3.174430e-20},
+ {344, 124, 3, 4, 40, 84, 1, 1.307736, 2.891760e-20},
+ {345, 116, 3, 4, 36, 36, 1, 1.307736, 2.799660e-20},
+ {346, 112, 3, 4, 30, 82, 1, 1.307736, 2.695640e-20},
+ {347, 128, 3, 4, 46, 46, 1, 1.307736, 2.167410e-20},
+ {348, 116, 3, 4, 34, 82, 1, 1.307736, 1.749650e-20},
+ {349, 120, 3, 4, 40, 40, 1, 1.307736, 1.587220e-20},
+ {350, 128, 3, 4, 44, 84, 1, 1.307736, 1.586440e-20},
+ {351, 124, 3, 4, 40, 40, 1, 1.307736, 1.445880e-20},
+ {352, 112, 3, 4, 30, 30, 1, 1.307736, 1.347820e-20},
+ {353, 120, 3, 4, 38, 82, 1, 1.307736, 1.054790e-20},
+ {354, 124, 3, 4, 38, 86, 1, 1.307736, 9.338320e-21},
+ {355, 116, 3, 4, 34, 34, 1, 1.345734, 8.748240e-21},
+ {356, 128, 3, 4, 44, 44, 1, 1.345734, 7.932220e-21},
+ {357, 128, 3, 4, 42, 86, 1, 1.345734, 5.474680e-21},
+ {358, 116, 3, 4, 32, 84, 1, 1.345734, 5.297010e-21},
+ {359, 120, 3, 4, 38, 38, 1, 1.345734, 5.273960e-21},
+ {360, 124, 3, 4, 38, 38, 1, 1.345734, 4.669160e-21},
+ {361, 120, 3, 4, 36, 84, 1, 1.345734, 3.349800e-21},
+ {362, 124, 3, 4, 36, 88, 1, 1.345734, 2.903950e-21},
+ {363, 128, 3, 4, 42, 42, 1, 1.345734, 2.737340e-21},
+ {364, 116, 3, 4, 32, 32, 1, 1.345734, 2.648510e-21},
+ {365, 128, 3, 4, 40, 88, 1, 1.345734, 1.798290e-21},
+ {366, 120, 3, 4, 36, 36, 1, 1.345734, 1.674900e-21},
+ {367, 124, 3, 4, 36, 36, 1, 1.345734, 1.451970e-21},
+ {368, 120, 3, 4, 34, 86, 1, 1.345734, 1.027330e-21},
+ {369, 128, 3, 4, 40, 40, 1, 1.345734, 8.991430e-22},
+ {370, 124, 3, 4, 34, 90, 1, 1.345734, 8.779540e-22},
+ {371, 128, 3, 4, 38, 90, 1, 1.345734, 5.674390e-22},
+ {372, 120, 3, 4, 34, 34, 1, 1.345734, 5.136640e-22},
+ {373, 124, 3, 4, 34, 34, 1, 1.345734, 4.389770e-22},
+ {374, 120, 3, 4, 32, 88, 1, 1.345734, 3.073590e-22},
+ {375, 128, 3, 4, 38, 38, 1, 1.345734, 2.837200e-22},
+ {376, 128, 3, 4, 36, 92, 1, 1.345734, 1.735640e-22},
+ {377, 120, 3, 4, 32, 32, 1, 1.345734, 1.536800e-22},
+ {378, 128, 3, 4, 36, 36, 1, 1.345734, 8.678180e-23},
+ {379, 128, 3, 4, 34, 94, 1, 1.345734, 5.192020e-23},
+ {380, 128, 3, 4, 34, 34, 1, 1.345734, 2.600000e-23},
+
+}
+
+/*
+// Table is difficulty table slice
+var Table = []difficulty{
+ {0, 32, 3, 4, 8, 24, 2, 0.329111, 3.077970e-05},
+ {1, 36, 3, 4, 9, 27, 2, 0.329111, 3.077970e-05},
+ {2, 40, 3, 4, 10, 30, 2, 0.329111, 2.023220e-05},
+ {3, 44, 3, 4, 11, 33, 1, 0.329111, 9.684650e-06},
+ {4, 48, 3, 4, 12, 36, 1, 0.329111, 6.784080e-06},
+ {5, 52, 3, 4, 13, 39, 2, 0.329111, 4.830240e-06},
+ {6, 56, 3, 4, 14, 42, 2, 0.369449, 3.125970e-06},
+ {7, 60, 3, 4, 15, 45, 1, 0.369449, 2.862890e-06},
+ {8, 64, 3, 4, 16, 48, 2, 0.369449, 1.637790e-06},
+ {9, 68, 3, 4, 17, 51, 1, 0.369449, 1.421700e-06},
+ {10, 72, 3, 4, 18, 54, 1, 0.369449, 1.051350e-06},
+ {11, 76, 3, 4, 19, 57, 2, 0.411046, 1.029740e-06},
+ {12, 80, 3, 4, 20, 60, 2, 0.411046, 7.570880e-07},
+ {13, 84, 3, 4, 21, 63, 1, 0.411046, 4.865630e-07},
+ {14, 88, 3, 4, 22, 66, 2, 0.411046, 4.813320e-07},
+ {15, 92, 3, 4, 23, 69, 1, 0.411046, 4.216920e-07},
+ {16, 96, 3, 4, 24, 72, 1, 0.411046, 3.350070e-07},
+ {17, 100, 3, 4, 25, 75, 2, 0.452453, 2.677070e-07},
+ {18, 104, 3, 4, 26, 78, 1, 0.452453, 2.055750e-07},
+ {19, 108, 3, 4, 27, 81, 1, 0.452453, 1.788400e-07},
+ {20, 112, 3, 4, 28, 84, 2, 0.452453, 1.664080e-07},
+ {21, 116, 3, 4, 29, 87, 1, 0.452453, 1.583110e-07},
+ {22, 120, 3, 4, 30, 90, 1, 0.452453, 7.917230e-08},
+ {23, 124, 3, 4, 31, 93, 1, 0.498513, 7.103820e-08},
+ {24, 128, 3, 4, 32, 96, 1, 0.498513, 6.510890e-08},
+ {25, 132, 3, 4, 33, 99, 1, 0.498513, 5.300760e-08},
+ {26, 136, 3, 4, 34, 102, 2, 0.498513, 4.266600e-08},
+ {27, 140, 3, 4, 35, 105, 1, 0.498513, 2.990510e-08},
+ {28, 144, 3, 4, 36, 108, 1, 0.498513, 2.927380e-08},
+ {29, 148, 3, 4, 37, 111, 2, 0.498513, 2.626790e-08},
+ {30, 152, 3, 4, 38, 114, 2, 0.498513, 1.485240e-08},
+ {31, 156, 3, 4, 39, 117, 1, 0.546238, 1.267290e-08},
+ {32, 160, 3, 4, 40, 120, 1, 0.546238, 9.891110e-09},
+ {33, 164, 3, 4, 41, 123, 2, 0.546238, 9.019200e-09},
+ {34, 168, 3, 4, 42, 126, 1, 0.546238, 8.762650e-09},
+ {35, 172, 3, 4, 43, 129, 1, 0.546238, 8.213140e-09},
+ {36, 176, 3, 4, 44, 132, 2, 0.546238, 6.658250e-09},
+ {37, 180, 3, 4, 45, 135, 1, 0.546238, 4.856960e-09},
+ {38, 184, 3, 4, 46, 138, 1, 0.546238, 4.381330e-09},
+ {39, 188, 3, 4, 47, 141, 2, 0.546238, 4.068000e-09},
+ {40, 192, 3, 4, 48, 144, 1, 0.546238, 3.186040e-09},
+ {41, 196, 3, 4, 49, 147, 1, 0.578290, 2.725470e-09},
+ {42, 200, 3, 4, 50, 150, 2, 0.578290, 2.410890e-09},
+ {43, 204, 3, 4, 51, 153, 1, 0.578290, 2.181360e-09},
+ {44, 208, 3, 4, 52, 156, 1, 0.578290, 1.737940e-09},
+ {45, 212, 3, 4, 53, 159, 1, 0.578290, 1.595330e-09},
+ {46, 216, 3, 4, 54, 162, 1, 0.578290, 1.481830e-09},
+ {47, 220, 3, 4, 55, 165, 2, 0.578290, 1.454780e-09},
+ {48, 224, 3, 4, 56, 168, 1, 0.578290, 1.250550e-09},
+ {49, 228, 3, 4, 57, 171, 1, 0.578290, 8.614860e-10},
+ {50, 232, 3, 4, 58, 174, 1, 0.578290, 7.976650e-10},
+ {51, 236, 3, 4, 59, 177, 1, 0.628015, 7.700380e-10},
+ {52, 240, 3, 4, 60, 180, 1, 0.628015, 6.978800e-10},
+ {53, 244, 3, 4, 61, 183, 1, 0.628015, 5.069080e-10},
+ {54, 248, 3, 4, 62, 186, 1, 0.628015, 4.986660e-10},
+ {55, 252, 3, 4, 63, 189, 1, 0.628015, 4.315180e-10},
+ {56, 256, 3, 4, 64, 192, 2, 0.628015, 3.848530e-10},
+}*/
+
diff --git a/consensus/kaiju/LDPC_utils.go b/consensus/kaiju/LDPC_utils.go
new file mode 100644
index 000000000000..ec2b209fcffa
--- /dev/null
+++ b/consensus/kaiju/LDPC_utils.go
@@ -0,0 +1,202 @@
+package kaiju
+
+import (
+ crand "crypto/rand"
+ "math"
+ "math/big"
+ "math/rand"
+
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+//Parameters for matrix and seed
+const (
+ BigInfinity = 1000000.0
+ Inf = 64.0
+ MaxNonce = 1<<32 - 1
+
+ // These parameters are only used for the decoding function.
+ maxIter = 20 // The maximum number of iteration in the decoder
+ crossErr = 0.01 // A transisient error probability. This is also fixed as a small value
+)
+
+type Parameters struct {
+ n int
+ m int
+ wc int
+ wr int
+ seed int
+}
+
+// setParameters sets n, wc, wr, m, seed return parameters and difficulty level
+func setParameters(header *types.Header) (Parameters, int) {
+ //level := SearchLevel(header.Difficulty)
+ level := SearchLevel(header.Difficulty)
+
+ parameters := Parameters{
+ n: Table[level].n,
+ wc: Table[level].wc,
+ wr: Table[level].wr,
+ }
+ parameters.m = int(parameters.n * parameters.wc / parameters.wr)
+ parameters.seed = generateSeed(header.ParentHash)
+
+ return parameters, level
+}
+
+// setParameters sets n, wc, wr, m, seed return parameters and difficulty level
+func setParameters_Seoul(header *types.Header) (Parameters, int) {
+ //level := SearchLevel(header.Difficulty)
+ level := SearchLevel_Seoul(header.Difficulty)
+ table := getTable(level)
+ parameters := Parameters{
+ n: table.n,
+ wc: table.wc,
+ wr: table.wr,
+ }
+ parameters.m = int(parameters.n * parameters.wc / parameters.wr)
+ parameters.seed = generateSeed(header.ParentHash)
+
+ return parameters, level
+}
+
+
+//generateRandomNonce generate 64bit random nonce with similar way of ethereum block nonce
+func generateRandomNonce() uint64 {
+ seed, _ := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
+ source := rand.New(rand.NewSource(seed.Int64()))
+
+ return uint64(source.Int63())
+}
+
+func funcF(x float64) float64 {
+ if x >= BigInfinity {
+ return 1.0 / BigInfinity
+ } else if x <= (1.0 / BigInfinity) {
+ return BigInfinity
+ } else {
+ return math.Log((math.Exp(x) + 1) / (math.Exp(x) - 1))
+ }
+}
+
+func infinityTest(x float64) float64 {
+ if x >= Inf {
+ return Inf
+ } else if x <= -Inf {
+ return -Inf
+ } else {
+ return x
+ }
+}
+
+//generateSeed generate seed using previous hash vector
+func generateSeed(phv [32]byte) int {
+ sum := 0
+ for i := 0; i < len(phv); i++ {
+ sum += int(phv[i])
+ }
+ return sum
+}
+
+//generateH generate H matrix using parameters
+//generateH Cannot be sure rand is same with original implementation of C++
+func generateH(parameters Parameters) [][]int {
+ var H [][]int
+ var hSeed int64
+ var colOrder []int
+
+ hSeed = int64(parameters.seed)
+ k := parameters.m / parameters.wc
+
+ H = make([][]int, parameters.m)
+ for i := range H {
+ H[i] = make([]int, parameters.n)
+ }
+
+ for i := 0; i < k; i++ {
+ for j := i * parameters.wr; j < (i+1)*parameters.wr; j++ {
+ H[i][j] = 1
+ }
+ }
+
+ for i := 1; i < parameters.wc; i++ {
+ colOrder = nil
+ for j := 0; j < parameters.n; j++ {
+ colOrder = append(colOrder, j)
+ }
+
+ src := rand.NewSource(hSeed)
+ rnd := rand.New(src)
+ rnd.Seed(hSeed)
+ rnd.Shuffle(len(colOrder), func(i, j int) {
+ colOrder[i],colOrder[j] = colOrder[j], colOrder[i]
+ })
+ hSeed--
+
+ for j := 0; j < parameters.n; j++ {
+ index := (colOrder[j]/parameters.wr + k*i)
+ H[index][j] = 1
+ }
+ }
+
+ return H
+}
+
+//generateQ generate colInRow and rowInCol matrix using H matrix
+func generateQ(parameters Parameters, H [][]int) ([][]int, [][]int) {
+ colInRow := make([][]int, parameters.wr)
+ for i := 0; i < parameters.wr; i++ {
+ colInRow[i] = make([]int, parameters.m)
+ }
+
+ rowInCol := make([][]int, parameters.wc)
+ for i := 0; i < parameters.wc; i++ {
+ rowInCol[i] = make([]int, parameters.n)
+ }
+
+ rowIndex := 0
+ colIndex := 0
+
+ for i := 0; i < parameters.m; i++ {
+ for j := 0; j < parameters.n; j++ {
+ if H[i][j] == 1 {
+ colInRow[colIndex%parameters.wr][i] = j
+ colIndex++
+
+ rowInCol[rowIndex/parameters.n][j] = i
+ rowIndex++
+ }
+ }
+ }
+
+ return colInRow, rowInCol
+}
+
+//generateHv generate hashvector
+//It needs to compare with origin C++ implementation Especially when sha256 function is used
+func generateHv(parameters Parameters, encryptedHeaderWithNonce []byte) []int {
+ hashVector := make([]int, parameters.n)
+
+ /*
+ if parameters.n <= 256 {
+ tmpHashVector = sha256.Sum256(headerWithNonce)
+ } else {
+ /*
+ This section is for a case in which the size of a hash vector is larger than 256.
+ This section will be implemented soon.
+ }
+ transform the constructed hexadecimal array into an binary array
+ ex) FE01 => 11111110000 0001
+ */
+
+ for i := 0; i < parameters.n/8; i++ {
+ decimal := int(encryptedHeaderWithNonce[i])
+ for j := 7; j >= 0; j-- {
+ hashVector[j+8*(i)] = decimal % 2
+ decimal /= 2
+ }
+ }
+
+ //outputWord := hashVector[:parameters.n]
+ return hashVector
+}
diff --git a/consensus/kaiju/algorithm.go b/consensus/kaiju/algorithm.go
new file mode 100644
index 000000000000..3456b8dcbeea
--- /dev/null
+++ b/consensus/kaiju/algorithm.go
@@ -0,0 +1,636 @@
+package kaiju
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "hash"
+ "math/big"
+ "math/rand"
+ "sync"
+ "time"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/consensus"
+ "github.com/cryptoecc/WorldLand/core/types"
+ "github.com/cryptoecc/WorldLand/crypto"
+ "github.com/cryptoecc/WorldLand/log"
+ "github.com/cryptoecc/WorldLand/metrics"
+ "github.com/cryptoecc/WorldLand/rpc"
+ "golang.org/x/crypto/sha3"
+)
+
+type ECC struct {
+ config Config
+
+ // Mining related fields
+ rand *rand.Rand // Properly seeded random source for nonces
+ threads int // Number of threads to mine on if mining
+ update chan struct{} // Notification channel to update mining parameters
+ hashrate metrics.Meter // Meter tracking the average hashrate
+ remote *remoteSealer
+
+ // Remote sealer related fields
+ workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer
+ fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work
+ submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result
+ fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
+ submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate
+
+ shared *ECC // Shared PoW verifier to avoid cache regeneration
+ fakeFail uint64 // Block number which fails PoW check even in fake mode
+ fakeDelay time.Duration // Time delay to sleep for before returning from verify
+
+ // VRF key pair for proof generation and verification
+ vrfPublicKey []byte // ED25519 public key (32 bytes)
+ vrfPrivateKey []byte // ED25519 private key (64 bytes)
+
+ lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
+ closeOnce sync.Once // Ensures exit channel will not be closed twice.
+}
+
+type Mode uint
+
+const (
+ // Existing epoch for DAG seed generation (DO NOT CHANGE)
+ epochLength = 30000 // Blocks per epoch for DAG seed hash - used by seedHash()
+
+ // Sortition epoch configuration (for VRF-based mining eligibility)
+ SortitionEpochLength = 100 // Blocks per sortition epoch (every 100 blocks)
+ SortitionSeedLookback = 10 // Blocks before sortition epoch boundary for seed (fork resistance)
+
+ ModeNormal Mode = iota
+ ModeShared
+ ModeTest
+ ModeFake
+ ModeFullFake
+)
+
+// SortitionEpoch returns the sortition epoch number for a given block number.
+// This is used for VRF-based mining eligibility, NOT for DAG generation.
+func SortitionEpoch(blockNumber uint64) uint64 {
+ return blockNumber / SortitionEpochLength
+}
+
+// SortitionEpochStartBlock returns the first block number of the given sortition epoch.
+func SortitionEpochStartBlock(epoch uint64) uint64 {
+ return epoch * SortitionEpochLength
+}
+
+// IsSortitionEpochStart checks if the given block number is at the start of a sortition epoch.
+func IsSortitionEpochStart(blockNumber uint64) bool {
+ return blockNumber%SortitionEpochLength == 0
+}
+
+// GetSortitionSeedBlockNumber returns the block number to use as seed for sortition.
+// Uses a block SortitionSeedLookback blocks before the sortition epoch boundary to resist fork attacks.
+func GetSortitionSeedBlockNumber(blockNumber uint64) uint64 {
+ epoch := SortitionEpoch(blockNumber)
+
+ if epoch == 0 {
+ return 0 // Genesis block for epoch 0
+ }
+
+ // Seed block = sortition epoch start - SortitionSeedLookback
+ epochStart := SortitionEpochStartBlock(epoch)
+ if epochStart > SortitionSeedLookback {
+ return epochStart - SortitionSeedLookback
+ }
+ return 0 // Fallback to genesis if not enough blocks
+}
+
+// GetSortitionSeedHash returns the hash to use as VRF input for sortition.
+// This retrieves the block hash from SortitionSeedLookback blocks before the sortition epoch boundary.
+func (ecc *ECC) GetSortitionSeedHash(chain consensus.ChainHeaderReader, blockNumber uint64) common.Hash {
+ seedBlockNum := GetSortitionSeedBlockNumber(blockNumber)
+
+ header := chain.GetHeaderByNumber(seedBlockNum)
+ if header == nil {
+ // Fallback to genesis if header not found
+ header = chain.GetHeaderByNumber(0)
+ if header == nil {
+ return common.Hash{}
+ }
+ }
+ return header.Hash()
+}
+
+// IsEligibleForSortitionEpoch checks if this miner is eligible to mine in the sortition epoch
+// containing the given block number, using VRF-based sortition.
+func (ecc *ECC) IsEligibleForSortitionEpoch(chain consensus.ChainHeaderReader, blockNumber uint64) (bool, []byte, error) {
+ ecc.lock.Lock()
+ defer ecc.lock.Unlock()
+
+ // Check if VRF keys are configured
+ if len(ecc.vrfPublicKey) == 0 || len(ecc.vrfPrivateKey) == 0 {
+ return false, nil, errors.New("VRF keys not configured")
+ }
+
+ // Get the seed hash for this sortition epoch
+ seedHash := ecc.GetSortitionSeedHash(chain, blockNumber)
+ if seedHash == (common.Hash{}) {
+ return false, nil, errors.New("failed to get sortition seed hash")
+ }
+
+ sortitionEpoch := SortitionEpoch(blockNumber)
+ seedBlockNum := GetSortitionSeedBlockNumber(blockNumber)
+
+ // Generate VRF proof using the seed hash
+ proof, hash, err := Prove(ecc.vrfPublicKey, ecc.vrfPrivateKey, seedHash.Bytes())
+ if err != nil {
+ return false, nil, fmt.Errorf("failed to generate VRF proof: %w", err)
+ }
+
+ // Check if the proof passes sortition
+ eligible := CheckSortition(proof)
+
+ log.Info("🎲 Sortition epoch check",
+ "sortitionEpoch", sortitionEpoch,
+ "blockNumber", blockNumber,
+ "seedBlock", seedBlockNum,
+ "seedHash", seedHash.Hex()[:16]+"...",
+ "vrfHash", hex.EncodeToString(hash)[:16]+"...",
+ "eligible", eligible)
+
+ return eligible, proof, nil
+}
+
+// Config are the configuration parameters of the ethash.
+type Config struct {
+ PowMode Mode
+ // When set, notifications sent by the remote sealer will
+ // be block header JSON objects instead of work package arrays.
+ NotifyFull bool
+ Log log.Logger `toml:"-"`
+}
+
+// hasher is a repetitive hasher allowing the same hash data structures to be
+// reused between hash runs instead of requiring new ones to be created.
+//var hasher func(dest []byte, data []byte)
+
+var (
+ two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
+
+ // sharedECC is a full instance that can be shared between multiple users.
+ sharedECC *ECC
+
+ // algorithmRevision is the data structure version used for file naming.
+ algorithmRevision = 2
+)
+
+func init() {
+ sharedConfig := Config{
+ PowMode: ModeNormal,
+ }
+ sharedECC = New(sharedConfig, nil, false)
+}
+
+type verifyParameters struct {
+ n uint64
+ m uint64
+ wc uint64
+ wr uint64
+ seed uint64
+ outputWord []uint64
+}
+
+//const cross_err = 0.01
+
+//type (
+// intMatrix [][]int
+// floatMatrix [][]float64
+//)
+
+// RunOptimizedConcurrencyLDPC use goroutine for mining block
+func RunOptimizedConcurrencyLDPC(header *types.Header, hash []byte) (bool, []int, []int, uint64, []byte) {
+ //Need to set difficulty before running LDPC
+ // Number of goroutines : 500, Number of attempts : 50000 Not bad
+
+ var LDPCNonce uint64
+ var hashVector []int
+ var outputWord []int
+ var digest []byte
+ var flag bool
+
+ //var wg sync.WaitGroup
+ //var outerLoopSignal = make(chan struct{})
+ //var innerLoopSignal = make(chan struct{})
+ //var goRoutineSignal = make(chan struct{})
+
+ parameters, _ := setParameters(header)
+ H := generateH(parameters)
+ colInRow, rowInCol := generateQ(parameters, H)
+
+ for i := 0; i < 64; i++ {
+ var goRoutineHashVector []int
+ var goRoutineOutputWord []int
+ goRoutineNonce := generateRandomNonce()
+ seed := make([]byte, 40)
+ copy(seed, hash)
+ binary.LittleEndian.PutUint64(seed[32:], goRoutineNonce)
+ seed = crypto.Keccak512(seed)
+ //fmt.Printf("nonce: %v\n", seed)
+
+ goRoutineHashVector = generateHv(parameters, seed)
+ goRoutineHashVector, goRoutineOutputWord, _ = OptimizedDecoding(parameters, goRoutineHashVector, H, rowInCol, colInRow)
+
+ flag, _ = MakeDecision(header, colInRow, goRoutineOutputWord)
+
+ if flag {
+ hashVector = goRoutineHashVector
+ outputWord = goRoutineOutputWord
+ LDPCNonce = goRoutineNonce
+ digest = seed
+ break
+ }
+ }
+ return flag, hashVector, outputWord, LDPCNonce, digest
+}
+
+func RunOptimizedConcurrencyLDPC_Seoul(header *types.Header, hash []byte) (bool, []int, []int, uint64, []byte) {
+ //Need to set difficulty before running LDPC
+ // Number of goroutines : 500, Number of attempts : 50000 Not bad
+
+ var LDPCNonce uint64
+ var hashVector []int
+ var outputWord []int
+ var digest []byte
+ var flag bool
+
+ //var wg sync.WaitGroup
+ //var outerLoopSignal = make(chan struct{})
+ //var innerLoopSignal = make(chan struct{})
+ //var goRoutineSignal = make(chan struct{})
+
+ parameters, _ := setParameters_Seoul(header)
+ H := generateH(parameters)
+ colInRow, rowInCol := generateQ(parameters, H)
+
+ for i := 0; i < 64; i++ {
+ var goRoutineHashVector []int
+ var goRoutineOutputWord []int
+ goRoutineNonce := generateRandomNonce()
+ seed := make([]byte, 40)
+ copy(seed, hash)
+ binary.LittleEndian.PutUint64(seed[32:], goRoutineNonce)
+ seed = crypto.Keccak512(seed)
+ //fmt.Printf("nonce: %v\n", seed)
+
+ goRoutineHashVector = generateHv(parameters, seed)
+ goRoutineHashVector, goRoutineOutputWord, _ = OptimizedDecodingSeoul(parameters, goRoutineHashVector, H, rowInCol, colInRow)
+
+ flag, _ = MakeDecision_Seoul(header, colInRow, goRoutineOutputWord)
+
+ if flag {
+ hashVector = goRoutineHashVector
+ outputWord = goRoutineOutputWord
+ LDPCNonce = goRoutineNonce
+ digest = seed
+ break
+ }
+ }
+ return flag, hashVector, outputWord, LDPCNonce, digest
+}
+
+// MakeDecision check outputWord is valid or not using colInRow
+func MakeDecision(header *types.Header, colInRow [][]int, outputWord []int) (bool, int) {
+ parameters, difficultyLevel := setParameters(header)
+ for i := 0; i < parameters.m; i++ {
+ sum := 0
+ for j := 0; j < parameters.wr; j++ {
+ // fmt.Printf("i : %d, j : %d, m : %d, wr : %d \n", i, j, m, wr)
+ sum = sum + outputWord[colInRow[j][i]]
+ }
+ if sum%2 == 1 {
+ return false, -1
+ }
+ }
+
+ var numOfOnes int
+ for _, val := range outputWord {
+ numOfOnes += val
+ }
+
+ if numOfOnes >= Table[difficultyLevel].decisionFrom &&
+ numOfOnes <= Table[difficultyLevel].decisionTo &&
+ numOfOnes%Table[difficultyLevel].decisionStep == 0 {
+ //fmt.Printf("hamming weight: %v\n", numOfOnes)
+ return true, numOfOnes
+ }
+
+ return false, numOfOnes
+}
+
+// MakeDecision check outputWord is valid or not using colInRow
+func MakeDecision_Seoul(header *types.Header, colInRow [][]int, outputWord []int) (bool, int) {
+ parameters, _ := setParameters_Seoul(header)
+ for i := 0; i < parameters.m; i++ {
+ sum := 0
+ for j := 0; j < parameters.wr; j++ {
+ // fmt.Printf("i : %d, j : %d, m : %d, wr : %d \n", i, j, m, wr)
+ sum = sum + outputWord[colInRow[j][i]]
+ }
+ if sum%2 == 1 {
+ return false, -1
+ }
+ }
+
+ var numOfOnes int
+ for _, val := range outputWord {
+ numOfOnes += val
+ }
+
+ if numOfOnes >= parameters.n/4 &&
+ numOfOnes <= parameters.n/4*3 {
+ //fmt.Printf("hamming weight: %v\n", numOfOnes)
+ return true, numOfOnes
+ }
+
+ return false, numOfOnes
+}
+
+//func isRegular(nSize, wCol, wRow int) bool {
+// res := float64(nSize*wCol) / float64(wRow)
+// m := math.Round(res)
+//
+// if int(m)*wRow == nSize*wCol {
+// return true
+// }
+//
+// return false
+//}
+
+//func SetDifficulty(nSize, wCol, wRow int) bool {
+// if isRegular(nSize, wCol, wRow) {
+// n = nSize
+// wc = wCol
+// wr = wRow
+// m = int(n * wc / wr)
+// return true
+// }
+// return false
+//}
+
+//func newIntMatrix(rows, cols int) intMatrix {
+// m := intMatrix(make([][]int, rows))
+// for i := range m {
+// m[i] = make([]int, cols)
+// }
+// return m
+//}
+//
+//func newFloatMatrix(rows, cols int) floatMatrix {
+// m := floatMatrix(make([][]float64, rows))
+// for i := range m {
+// m[i] = make([]float64, cols)
+// }
+// return m
+//}
+
+// New creates a full sized ethash PoW scheme and starts a background thread for
+// remote mining, also optionally notifying a batch of remote services of new work
+// packages.
+
+func New(config Config, notify []string, noverify bool) *ECC {
+
+ println("starting kaiju engine")
+
+ if config.Log == nil {
+ config.Log = log.Root()
+ }
+ ecc := &ECC{
+ config: config,
+ update: make(chan struct{}),
+ hashrate: metrics.NewMeterForced(),
+ workCh: make(chan *sealTask),
+ fetchWorkCh: make(chan *sealWork),
+ submitWorkCh: make(chan *mineResult),
+ fetchRateCh: make(chan chan uint64),
+ submitRateCh: make(chan *hashrate),
+ }
+ if config.PowMode == ModeShared {
+ ecc.shared = sharedECC
+ }
+ ecc.remote = startRemoteSealer(ecc, notify, noverify)
+ return ecc
+}
+
+func NewTester(notify []string, noverify bool) *ECC {
+ ecc := &ECC{
+ config: Config{PowMode: ModeTest},
+ update: make(chan struct{}),
+ hashrate: metrics.NewMeterForced(),
+ workCh: make(chan *sealTask),
+ fetchWorkCh: make(chan *sealWork),
+ submitWorkCh: make(chan *mineResult),
+ fetchRateCh: make(chan chan uint64),
+ submitRateCh: make(chan *hashrate),
+ }
+ ecc.remote = startRemoteSealer(ecc, notify, noverify)
+ return ecc
+}
+
+// NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts
+// all blocks' seal as valid, though they still have to conform to the Ethereum
+// consensus rules.
+func NewFaker() *ECC {
+ return &ECC{
+ config: Config{
+ PowMode: ModeFake,
+ Log: log.Root(),
+ },
+ }
+}
+
+// NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that
+// accepts all blocks as valid apart from the single one specified, though they
+// still have to conform to the Ethereum consensus rules.
+func NewFakeFailer(fail uint64) *ECC {
+ return &ECC{
+ config: Config{
+ PowMode: ModeFake,
+ Log: log.Root(),
+ },
+ fakeFail: fail,
+ }
+}
+
+// NewFakeDelayer creates a ethash consensus engine with a fake PoW scheme that
+// accepts all blocks as valid, but delays verifications by some time, though
+// they still have to conform to the Ethereum consensus rules.
+func NewFakeDelayer(delay time.Duration) *ECC {
+ return &ECC{
+ config: Config{
+ PowMode: ModeFake,
+ Log: log.Root(),
+ },
+ fakeDelay: delay,
+ }
+}
+
+// NewFullFaker creates an ethash consensus engine with a full fake scheme that
+// accepts all blocks as valid, without checking any consensus rules whatsoever.
+func NewFullFaker() *ECC {
+ return &ECC{
+ config: Config{
+ PowMode: ModeFullFake,
+ Log: log.Root(),
+ },
+ }
+}
+
+// NewShared creates a full sized ethash PoW shared between all requesters running
+// in the same process.
+//func NewShared() *ECC {
+// return &ECC{shared: sharedECC}
+//}
+
+// Close closes the exit channel to notify all backend threads exiting.
+func (ecc *ECC) Close() error {
+ return ecc.StopRemoteSealer()
+}
+
+// StopRemoteSealer stops the remote sealer
+func (ecc *ECC) StopRemoteSealer() error {
+ ecc.closeOnce.Do(func() {
+ // Short circuit if the exit channel is not allocated.
+ if ecc.remote == nil {
+ return
+ }
+ close(ecc.remote.requestExit)
+ <-ecc.remote.exitCh
+ })
+ return nil
+}
+
+// Threads returns the number of mining threads currently enabled. This doesn't
+// necessarily mean that mining is running!
+func (ecc *ECC) Threads() int {
+ ecc.lock.Lock()
+ defer ecc.lock.Unlock()
+
+ return ecc.threads
+}
+
+// SetThreads updates the number of mining threads currently enabled. Calling
+// this method does not start mining, only sets the thread count. If zero is
+// specified, the miner will use all cores of the machine. Setting a thread
+// count below zero is allowed and will cause the miner to idle, without any
+// work being done.
+func (ecc *ECC) SetThreads(threads int) {
+ ecc.lock.Lock()
+ defer ecc.lock.Unlock()
+
+ // If we're running a shared PoW, set the thread count on that instead
+ if ecc.shared != nil {
+ ecc.shared.SetThreads(threads)
+ return
+ }
+ // Update the threads and ping any running seal to pull in any changes
+ ecc.threads = threads
+ select {
+ case ecc.update <- struct{}{}:
+ default:
+ }
+}
+
+// SetVRFKeys sets the VRF key pair used for proof generation
+// The publicKey should be 32 bytes (ED25519 public key)
+// The privateKey should be 64 bytes (ED25519 private key)
+func (ecc *ECC) SetVRFKeys(publicKey, privateKey []byte) {
+ ecc.lock.Lock()
+ defer ecc.lock.Unlock()
+
+ ecc.vrfPublicKey = make([]byte, len(publicKey))
+ copy(ecc.vrfPublicKey, publicKey)
+
+ ecc.vrfPrivateKey = make([]byte, len(privateKey))
+ copy(ecc.vrfPrivateKey, privateKey)
+}
+
+// Hashrate implements PoW, returning the measured rate of the search invocations
+// per second over the last minute.
+// Note the returned hashrate includes local hashrate, but also includes the total
+// hashrate of all remote miner.
+func (ecc *ECC) Hashrate() float64 {
+ // Short circuit if we are run the ecc in normal/test mode.
+
+ var res = make(chan uint64, 1)
+
+ select {
+ case ecc.remote.fetchRateCh <- res:
+ case <-ecc.remote.exitCh:
+ // Return local hashrate only if ecc is stopped.
+ return ecc.hashrate.Rate1()
+ }
+
+ // Gather total submitted hash rate of remote sealers.
+ return ecc.hashrate.Rate1() + float64(<-res)
+}
+
+// APIs implements consensus.Engine, returning the user facing RPC APIs.
+func (ecc *ECC) APIs(chain consensus.ChainHeaderReader) []rpc.API {
+ // In order to ensure backward compatibility, we exposes ecc RPC APIs
+ // to both eth and ecc namespaces.
+ return []rpc.API{
+ {
+ Namespace: "eth",
+ Version: "1.0",
+ Service: &API{ecc},
+ Public: true,
+ },
+ {
+ Namespace: "ecc",
+ Version: "1.0",
+ Service: &API{ecc},
+ Public: true,
+ },
+ }
+}
+
+// hasher is a repetitive hasher allowing the same hash data structures to be
+// reused between hash runs instead of requiring new ones to be created.
+type hasher func(dest []byte, data []byte)
+
+// makeHasher creates a repetitive hasher, allowing the same hash data structures to
+// be reused between hash runs instead of requiring new ones to be created. The returned
+// function is not thread safe!
+func makeHasher(h hash.Hash) hasher {
+ // sha3.state supports Read to get the sum, use it to avoid the overhead of Sum.
+ // Read alters the state but we reset the hash before every operation.
+ type readerHash interface {
+ hash.Hash
+ Read([]byte) (int, error)
+ }
+ rh, ok := h.(readerHash)
+ if !ok {
+ panic("can't find Read method on hash")
+ }
+ outputLen := rh.Size()
+ return func(dest []byte, data []byte) {
+ rh.Reset()
+ rh.Write(data)
+ rh.Read(dest[:outputLen])
+ }
+}
+
+// seedHash is the seed to use for generating a verification cache and the mining
+// dataset.
+func seedHash(block uint64) []byte {
+ seed := make([]byte, 32)
+ if block < epochLength {
+ return seed
+ }
+ keccak256 := makeHasher(sha3.NewLegacyKeccak256())
+ for i := 0; i < int(block/epochLength); i++ {
+ keccak256(seed, seed)
+ }
+ return seed
+}
+
+// // SeedHash is the seed to use for generating a verification cache and the mining
+// // dataset.
+func SeedHash(block uint64) []byte {
+ return seedHash(block)
+}
diff --git a/consensus/kaiju/algorithm_test.go b/consensus/kaiju/algorithm_test.go
new file mode 100644
index 000000000000..366b52c7d368
--- /dev/null
+++ b/consensus/kaiju/algorithm_test.go
@@ -0,0 +1,90 @@
+package kaiju
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/common/hexutil"
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+func TestRandomSeed(t *testing.T) {
+ header := new(types.Header)
+ header.Difficulty = ProbToDifficulty(Table[0].miningProb)
+ parameters, _ := setParameters(header)
+
+ a := generateH(parameters)
+ b := generateH(parameters)
+
+ if !reflect.DeepEqual(a, b) {
+ t.Error("Wrong matrix")
+ } else {
+ t.Log("Pass")
+ }
+}
+
+func TestLDPC(t *testing.T) {
+ /*
+ prevHash := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000000")
+ curHash := hexutil.MustDecode("0xca2ff06caae7c94dc968be7d76d0fbf60dd2e1989ee9bf0d5931e48564d5143b")
+ nonce, mixDigest := RunLDPC(prevHash, curHash)
+
+ wantDigest := hexutil.MustDecode("0x535306ee4b42c92aecd0e71fca98572064f049c2babb2769faa3bbd87d67ec2d")
+
+ if !bytes.Equal(mixDigest, wantDigest) {
+ t.Errorf("light hashimoto digest mismatch: have %x, want %x", mixDigest, wantDigest)
+ }
+
+ t.Log(nonce)
+ */
+ header := new(types.Header)
+ //t.Log(hexutil.Encode(header.ParentHash))
+ header.Difficulty = ProbToDifficulty(Table[0].miningProb)
+ var hash []byte
+ _, hashVector, outputWord, LDPCNonce, digest := RunOptimizedConcurrencyLDPC(header, hash)
+
+ t.Logf("Hash vector : %v\n", hashVector)
+ t.Logf("Outputword : %v\n", outputWord)
+ t.Logf("LDPC Nonce : %v\n", LDPCNonce)
+ t.Logf("Digest : %v\n", digest)
+}
+
+func BenchmarkECCPoW(b *testing.B) {
+ //prevHash := hexutil.MustDecode("0xd783efa4d392943503f28438ad5830b2d5964696ffc285f338585e9fe0a37a05")
+ //curHash := hexutil.MustDecode("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
+
+ header := new(types.Header)
+ header.Difficulty = ProbToDifficulty(Table[0].miningProb)
+ var hash []byte
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ RunOptimizedConcurrencyLDPC(header, hash)
+ }
+}
+
+
+func TestHashRate(t *testing.T) {
+ var (
+ hashrate = []hexutil.Uint64{100, 200, 300}
+ expect uint64
+ ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")}
+ )
+ ecc := NewTester(nil, false)
+ defer ecc.Close()
+
+ if tot := ecc.Hashrate(); tot != 0 {
+ t.Error("expect the result should be zero")
+ }
+
+ api := &API{ecc}
+ for i := 0; i < len(hashrate); i++ {
+ if res := api.SubmitHashRate(hashrate[i], ids[i]); !res {
+ t.Error("remote miner submit hashrate failed")
+ }
+ expect += uint64(hashrate[i])
+ }
+ if tot := ecc.Hashrate(); tot != float64(expect) {
+ t.Error("expect total hashrate should be same")
+ }
+}
diff --git a/consensus/kaiju/api.go b/consensus/kaiju/api.go
new file mode 100644
index 000000000000..aa62dd4f1a89
--- /dev/null
+++ b/consensus/kaiju/api.go
@@ -0,0 +1,116 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package kaiju
+
+import (
+ "errors"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/common/hexutil"
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+var erreccStopped = errors.New("ecc stopped")
+
+// API exposes ecc related methods for the RPC interface.
+type API struct {
+ ecc *ECC // Make sure the mode of ecc is normal.
+}
+
+// GetWork returns a work package for external miner.
+//
+// The work package consists of 3 strings:
+// result[0] - 32 bytes hex encoded current block header pow-hash
+// result[1] - 32 bytes hex encoded seed hash used for DAG
+// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
+// result[3] - hex encoded block number
+func (api *API) GetWork() ([4]string, error) {
+ //if api.ecc.config.PowMode != ModeNormal && api.ecc.config.PowMode != ModeTest {
+ // return [4]string{}, errors.New("not supported")
+ //}
+
+ var (
+ workCh = make(chan [4]string, 1)
+ errc = make(chan error, 1)
+ )
+
+ select {
+ case api.ecc.fetchWorkCh <- &sealWork{errc: errc, res: workCh}:
+ case <-api.ecc.remote.exitCh:
+ return [4]string{}, erreccStopped
+ }
+
+ select {
+ case work := <-workCh:
+ return work, nil
+ case err := <-errc:
+ return [4]string{}, err
+ }
+}
+
+// SubmitWork can be used by external miner to submit their POW solution.
+// It returns an indication if the work was accepted.
+// Note either an invalid solution, a stale work a non-existent work will return false.
+func (api *API) SubmitWork(nonce types.BlockNonce, hash, digest common.Hash) bool {
+ //if api.ecc.config.PowMode != ModeNormal && api.ecc.config.PowMode != ModeTest {
+ // return false
+ //}
+
+ var errc = make(chan error, 1)
+
+ select {
+ case api.ecc.submitWorkCh <- &mineResult{
+ nonce: nonce,
+ mixDigest: digest,
+ hash: hash,
+ errc: errc,
+ }:
+ case <-api.ecc.remote.exitCh:
+ return false
+ }
+
+ err := <-errc
+ return err == nil
+}
+
+// SubmitHashrate can be used for remote miners to submit their hash rate.
+// This enables the node to report the combined hash rate of all miners
+// which submit work through this node.
+//
+// It accepts the miner hash rate and an identifier which must be unique
+// between nodes.
+func (api *API) SubmitHashRate(rate hexutil.Uint64, id common.Hash) bool {
+
+ var done = make(chan struct{}, 1)
+
+ select {
+ case api.ecc.submitRateCh <- &hashrate{done: done, rate: uint64(rate), id: id}:
+ case <-api.ecc.remote.exitCh:
+ return false
+ }
+
+ // Block until hash rate submitted successfully.
+ <-done
+
+ return true
+}
+
+// Geccrate returns the current hashrate for local CPU miner and remote miner.
+func (api *API) Geccrate() uint64 {
+
+ return uint64(api.ecc.Hashrate())
+}
diff --git a/consensus/kaiju/consensus.go b/consensus/kaiju/consensus.go
new file mode 100644
index 000000000000..6985cab43a74
--- /dev/null
+++ b/consensus/kaiju/consensus.go
@@ -0,0 +1,601 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package kaiju
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math/big"
+ "runtime"
+ "time"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/consensus"
+ "github.com/cryptoecc/WorldLand/consensus/misc"
+ "github.com/cryptoecc/WorldLand/core/state"
+ "github.com/cryptoecc/WorldLand/core/types"
+ "github.com/cryptoecc/WorldLand/log"
+ "github.com/cryptoecc/WorldLand/params"
+ "github.com/cryptoecc/WorldLand/rlp"
+ "github.com/cryptoecc/WorldLand/trie"
+ mapset "github.com/deckarep/golang-set"
+ "golang.org/x/crypto/sha3"
+)
+
+// ecc proof-of-work protocol constants.
+var (
+ FrontierBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
+ ByzantiumBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
+ ConstantinopleBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople
+ WorldLandBlockReward = big.NewInt(4e+18) //Block reward in wei for successfully mining a block upward from WorldLand
+ //WorldLandFirstBlockReward = big.NewInt(9e+18) //Block reward in wei for successfully mining a genesisblock upward from WorldLand
+
+ HALVING_INTERVAL = uint64(6307200) //Block per year * 2year
+ MATURITY_INTERVAL = uint64(3153600) //Block per year
+
+ SumRewardUntilMaturity = big.NewInt(47304000) //Total supply of token until maturity
+
+ MaxHalving = int64(4)
+
+ maxUncles = 2 // Maximum number of uncles allowed in a single block
+ allowedFutureBlockTimeSeconds = int64(15) // Max seconds from current time allowed for blocks, before they're considered future blocks
+
+)
+
+// Various error messages to mark blocks invalid. These should be private to
+// prevent engine specific errors from being referenced in the remainder of the
+// codebase, inherently breaking if the engine is swapped out. Please put common
+// error types into the consensus package.
+var (
+ errLargeBlockTime = errors.New("timestamp too big")
+ errZeroBlockTime = errors.New("timestamp equals parent's")
+ errTooManyUncles = errors.New("too many uncles")
+ errDuplicateUncle = errors.New("duplicate uncle")
+ errUncleIsAncestor = errors.New("uncle is ancestor")
+ errDanglingUncle = errors.New("uncle's parent is not ancestor")
+ errInvalidDifficulty = errors.New("non-positive difficulty")
+ errInvalidMixDigest = errors.New("invalid mix digest")
+ errInvalidPoW = errors.New("invalid proof-of-work")
+)
+
+// Author implements consensus.Engine, returning the header's coinbase as the
+// proof-of-work verified author of the block.
+func (ecc *ECC) Author(header *types.Header) (common.Address, error) {
+ return header.Coinbase, nil
+}
+
+// VerifyHeader checks whether a header conforms to the consensus rules of the
+// stock Ethereum ecc engine.
+func (ecc *ECC) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error {
+ // If we're running a full engine faking, accept any input as valid
+ if ecc.config.PowMode == ModeFullFake {
+ return nil
+ }
+ // Short circuit if the header is known, or it's parent not
+ number := header.Number.Uint64()
+ if chain.GetHeader(header.Hash(), number) != nil {
+ return nil
+ }
+ parent := chain.GetHeader(header.ParentHash, number-1)
+ if parent == nil {
+ return consensus.ErrUnknownAncestor
+ }
+ // Sanity checks passed, do a proper verification
+ return ecc.verifyHeader(chain, header, parent, false, seal, time.Now().Unix())
+}
+
+// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
+// concurrently. The method returns a quit channel to abort the operations and
+// a results channel to retrieve the async verifications.
+func (ecc *ECC) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
+ // If we're running a full engine faking, accept any input as valid
+ if ecc.config.PowMode == ModeFullFake || len(headers) == 0 {
+ abort, results := make(chan struct{}), make(chan error, len(headers))
+ for i := 0; i < len(headers); i++ {
+ results <- nil
+ }
+ return abort, results
+ }
+ // Spawn as many workers as allowed threads
+ workers := runtime.GOMAXPROCS(0)
+ if len(headers) < workers {
+ workers = len(headers)
+ }
+
+ // Create a task channel and spawn the verifiers
+ var (
+ inputs = make(chan int)
+ done = make(chan int, workers)
+ errors = make([]error, len(headers))
+ abort = make(chan struct{})
+ unixNow = time.Now().Unix()
+ )
+ for i := 0; i < workers; i++ {
+ go func() {
+ for index := range inputs {
+ errors[index] = ecc.verifyHeaderWorker(chain, headers, seals, index, unixNow)
+ done <- index
+ }
+ }()
+ }
+
+ errorsOut := make(chan error, len(headers))
+ go func() {
+ defer close(inputs)
+ var (
+ in, out = 0, 0
+ checked = make([]bool, len(headers))
+ inputs = inputs
+ )
+ for {
+ select {
+ case inputs <- in:
+ if in++; in == len(headers) {
+ // Reached end of headers. Stop sending to workers.
+ inputs = nil
+ }
+ case index := <-done:
+ for checked[index] = true; checked[out]; out++ {
+ errorsOut <- errors[out]
+ if out == len(headers)-1 {
+ return
+ }
+ }
+ case <-abort:
+ return
+ }
+ }
+ }()
+ return abort, errorsOut
+}
+
+func (ecc *ECC) verifyHeaderWorker(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool, index int, unixNow int64) error {
+ var parent *types.Header
+ if index == 0 {
+ parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
+ } else if headers[index-1].Hash() == headers[index].ParentHash {
+ parent = headers[index-1]
+ }
+ if parent == nil {
+ return consensus.ErrUnknownAncestor
+ }
+ return ecc.verifyHeader(chain, headers[index], parent, false, seals[index], unixNow)
+}
+
+// VerifyUncles verifies that the given block's uncles conform to the consensus
+// rules of the stock Ethereum ecc engine.
+func (ecc *ECC) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
+ // If we're running a full engine faking, accept any input as valid
+ if ecc.config.PowMode == ModeFullFake {
+ return nil
+ }
+ // Verify that there are at most 2 uncles included in this block
+ if len(block.Uncles()) > maxUncles {
+ return errTooManyUncles
+ }
+ if len(block.Uncles()) == 0 {
+ return nil
+ }
+ // Gather the set of past uncles and ancestors
+ uncles, ancestors := mapset.NewSet(), make(map[common.Hash]*types.Header)
+
+ number, parent := block.NumberU64()-1, block.ParentHash()
+
+ for i := 0; i < 7; i++ {
+ ancestorHeader := chain.GetHeader(parent, number)
+ if ancestorHeader == nil {
+ break
+ }
+ ancestors[parent] = ancestorHeader
+ // If the ancestor doesn't have any uncles, we don't have to iterate them
+ if ancestorHeader.UncleHash != types.EmptyUncleHash {
+ // Need to add those uncles to the banned list too
+ ancestor := chain.GetBlock(parent, number)
+ if ancestor == nil {
+ break
+ }
+ for _, uncle := range ancestor.Uncles() {
+ uncles.Add(uncle.Hash())
+ }
+ }
+ parent, number = ancestorHeader.ParentHash, number-1
+ }
+ ancestors[block.Hash()] = block.Header()
+ uncles.Add(block.Hash())
+
+ // Verify each of the uncles that it's recent, but not an ancestor
+ for _, uncle := range block.Uncles() {
+ // Make sure every uncle is rewarded only once
+ hash := uncle.Hash()
+ if uncles.Contains(hash) {
+ return errDuplicateUncle
+ }
+ uncles.Add(hash)
+
+ // Make sure the uncle has a valid ancestry
+ if ancestors[hash] != nil {
+ return errUncleIsAncestor
+ }
+ if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == block.ParentHash() {
+ return errDanglingUncle
+ }
+ if err := ecc.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, true, time.Now().Unix()); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// verifyHeader checks whether a header conforms to the consensus rules of the
+// stock Ethereum ecc engine.
+// See YP section 4.3.4. "Block Header Validity"
+func (ecc *ECC) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, uncle bool, seal bool, unixNow int64) error {
+ // Ensure that the header's extra-data section is of a reasonable size
+ if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
+ return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
+ }
+ // Verify the header's timestamp
+ if !uncle {
+ if header.Time > uint64(unixNow+allowedFutureBlockTimeSeconds) {
+ //log.Println(unixNow)
+ //log.Println(allowedFutureBlockTimeSeconds)
+ //log.Println(header.Time)
+ return consensus.ErrFutureBlock
+ }
+ }
+
+ if header.Time <= parent.Time {
+ return errZeroBlockTime
+ }
+ // Verify the block's difficulty based in it's timestamp and parent's difficulty
+ expectDiff := ecc.CalcDifficulty(chain, header.Time, parent)
+
+ if expectDiff.Cmp(header.Difficulty) != 0 {
+ return fmt.Errorf("invalid ecc difficulty: have %v, want %v", header.Difficulty, expectDiff)
+ }
+
+ // Verify that the gas limit is <= 2^63-1
+ if header.GasLimit > params.MaxGasLimit {
+ return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
+ }
+ // Verify that the gasUsed is <= gasLimit
+ if header.GasUsed > header.GasLimit {
+ return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
+ }
+
+ // Verify the block's gas usage and (if applicable) verify the base fee.
+ if !chain.Config().IsLondon(header.Number) {
+ // Verify BaseFee not present before EIP-1559 fork.
+ if header.BaseFee != nil {
+ return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)
+ }
+ if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
+ return err
+ }
+ } else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
+ // Verify the header's EIP-1559 attributes.
+ return err
+ }
+ // Verify that the block number is parent's +1
+ if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
+ return consensus.ErrInvalidNumber
+ }
+ // Verify the engine specific seal securing the block
+ if seal {
+ if err := ecc.verifySeal(chain, header); err != nil {
+ return err
+ }
+ }
+ // Verify VRF proof for epoch sortition
+ if err := ecc.verifyVRFProof(chain, header); err != nil {
+ return err
+ }
+ // If all checks passed, validate any special fields for hard forks
+ if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil {
+ return err
+ }
+ if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil {
+ return err
+ }
+ return nil
+}
+
+// CalcDifficulty is the difficulty adjustment algorithm. It returns
+// the difficulty that a new block should have when created at time
+// given the parent block's time and difficulty.
+func (ecc *ECC) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
+ next := new(big.Int).Add(parent.Number, big1)
+ switch {
+ case chain.Config().IsAnnapurna(next):
+ return calcDifficultyAnnapurna(chain, time, parent)
+ case chain.Config().IsSeoul(next):
+ return calcDifficultySeoul(chain, time, parent)
+
+ //return calcDifficultyFrontier(time, parent)
+ default:
+ //fmt.Println("frontier")
+ return calcDifficultyFrontier(time, parent)
+ }
+
+ //return CalcDifficulty(chain.Config(), time, parent)
+}
+
+// CalcDifficulty is the difficulty adjustment algorithm. It returns
+// the difficulty that a new block should have when created at time
+// given the parent block's time and difficulty.
+/*func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
+ next := new(big.Int).Add(parent.Number, big1)
+ switch {
+ case config.IsSeoul(next):
+ return calcDifficultySeoul(time, parent)
+ default:
+ //fmt.Println("frontier")
+ return calcDifficultyFrontier(time, parent)
+ }
+}*/
+
+// Some weird constants to avoid constant memory allocs for them.
+var (
+ expDiffPeriod = big.NewInt(100000)
+ big1 = big.NewInt(1)
+ big2 = big.NewInt(2)
+ big9 = big.NewInt(9)
+ big10 = big.NewInt(10)
+ bigMinus99 = big.NewInt(-99)
+)
+
+// makeDifficultyCalculator creates a difficultyCalculator with the given bomb-delay.
+// the difficulty is calculated with Byzantium rules, which differs from Homestead in
+// how uncles affect the calculation
+func makeDifficultyCalculator(bombDelay *big.Int) func(time uint64, parent *types.Header) *big.Int {
+ return MakeLDPCDifficultyCalculator()
+}
+
+// calcDifficultyFrontier is the difficulty adjustment algorithm. It returns the
+// difficulty that a new block should have when created at time given the parent
+// block's time and difficulty. The calculation uses the Frontier rules.
+func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int {
+ difficultyCalculator := MakeLDPCDifficultyCalculator()
+ return difficultyCalculator(time, parent)
+}
+
+func calcDifficultySeoul(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
+ difficultyCalculator := MakeLDPCDifficultyCalculator_Seoul()
+ //return difficultyCalculator(chain, time, parent)
+ return difficultyCalculator(time, parent)
+}
+
+func calcDifficultyAnnapurna(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
+ difficultyCalculator := MakeLDPCDifficultyCalculatorAnnapurna()
+ //return difficultyCalculator(chain, time, parent)
+ return difficultyCalculator(time, parent)
+}
+
+// Exported for fuzzing
+var FrontierDifficultyCalculator = calcDifficultyFrontier
+var DynamicDifficultyCalculator = makeDifficultyCalculator
+
+// verifySeal checks whether a block satisfies the PoW difficulty requirements,
+// either using the usual ecc cache for it, or alternatively using a full DAG
+// to make remote mining fast.
+func (ecc *ECC) verifySeal(chain consensus.ChainHeaderReader, header *types.Header) error {
+ // If we're running a fake PoW, accept any seal as valid
+ if ecc.config.PowMode == ModeFake || ecc.config.PowMode == ModeFullFake {
+ time.Sleep(ecc.fakeDelay)
+ if ecc.fakeFail == header.Number.Uint64() {
+ return errInvalidPoW
+ }
+ return nil
+ }
+ // If we're running a shared PoW, delegate verification to it
+ if ecc.shared != nil {
+ return ecc.shared.verifySeal(chain, header)
+ }
+ // Ensure that we have a valid difficulty for the block
+ if header.Difficulty.Sign() <= 0 {
+ return errInvalidDifficulty
+ }
+
+ var (
+ digest []byte
+ flag bool
+ )
+ if chain.Config().IsSeoul(header.Number) {
+ //fmt.Println("Seoul")
+ flag, _, _, digest = VerifyOptimizedDecodingSeoul(header, ecc.SealHash(header).Bytes())
+ } else {
+ flag, _, _, digest = VerifyOptimizedDecoding(header, ecc.SealHash(header).Bytes())
+ }
+
+ encodedDigest := common.BytesToHash(digest)
+ if !bytes.Equal(header.MixDigest[:], encodedDigest[:]) {
+ return errInvalidMixDigest
+ }
+
+ if flag == false {
+ return errInvalidPoW
+ }
+
+ return nil
+}
+
+// verifyVRFProof checks whether the VRF proof in the header is valid for epoch sortition.
+// The proof must be generated using the epoch seed hash (block hash from SeedLookback blocks
+// before the epoch boundary) to prevent fork-based manipulation.
+func (ecc *ECC) verifyVRFProof(chain consensus.ChainHeaderReader, header *types.Header) error {
+
+ if header.VRFProof == nil || len(header.VRFProof) == 0 {
+ return errors.New("VRF proof is required but missing")
+ }
+
+ // VRF public key must be present
+ if header.VRFPublicKey == nil || len(header.VRFPublicKey) == 0 {
+ return errors.New("VRF public key is required but missing")
+ }
+
+ // Get the sortition seed hash for verification
+ // This uses the same seed block that the miner used for sortition
+ blockNumber := header.Number.Uint64()
+ seedHash := ecc.GetSortitionSeedHash(chain, blockNumber)
+ if seedHash == (common.Hash{}) {
+ return errors.New("failed to get sortition seed hash for verification")
+ }
+
+ // Verify the VRF proof using the sortition seed hash as the message
+ valid, err := Verify(header.VRFPublicKey, header.VRFProof, seedHash.Bytes())
+ if err != nil {
+ return fmt.Errorf("VRF verification error: %w", err)
+ }
+ if !valid {
+ return errors.New("invalid VRF proof for sortition seed")
+ }
+
+ // Check if the VRF proof passes sortition criteria
+ if !CheckSortition(header.VRFProof) {
+ return errors.New("VRF proof does not pass sortition criteria")
+ }
+
+ sortitionEpoch := SortitionEpoch(blockNumber)
+ seedBlockNum := GetSortitionSeedBlockNumber(blockNumber)
+ log.Debug("✅ VRF sortition verified",
+ "sortitionEpoch", sortitionEpoch,
+ "block", blockNumber,
+ "seedBlock", seedBlockNum)
+
+ return nil
+}
+
+// Prepare implements consensus.Engine, initializing the difficulty field of a
+// header to conform to the ecc protocol. The changes are done inline.
+func (ecc *ECC) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
+ parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
+ if parent == nil {
+ return consensus.ErrUnknownAncestor
+ }
+ header.Difficulty = ecc.CalcDifficulty(chain, header.Time, parent)
+
+ return nil
+}
+
+// Finalize implements consensus.Engine, accumulating the block and uncle rewards,
+// setting the final state and assembling the block.
+func (ecc *ECC) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
+ // Accumulate any block and uncle rewards and commit the final state root
+ accumulateRewards(chain.Config(), state, header, uncles)
+ header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
+}
+
+func (ecc *ECC) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
+ // Accumulate any block and uncle rewards and commit the final state root
+ ecc.Finalize(chain, header, state, txs, uncles)
+
+ // Header seems complete, assemble into a block and return
+ return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil
+}
+
+// SealHash returns the hash of a block prior to it being sealed.
+func (ecc *ECC) SealHash(header *types.Header) (hash common.Hash) {
+ hasher := sha3.NewLegacyKeccak256()
+
+ enc := []interface{}{
+ header.ParentHash,
+ header.UncleHash,
+ header.Coinbase,
+ header.Root,
+ header.TxHash,
+ header.ReceiptHash,
+ header.Bloom,
+ header.Difficulty,
+ header.Number,
+ header.GasLimit,
+ header.GasUsed,
+ header.Time,
+ header.Extra,
+ }
+ if header.BaseFee != nil {
+ enc = append(enc, header.BaseFee)
+ }
+
+ rlp.Encode(hasher, enc)
+ hasher.Sum(hash[:0])
+ return hash
+}
+
+// Some weird constants to avoid constant memory allocs for them.
+var (
+ big8 = big.NewInt(8)
+ big32 = big.NewInt(32)
+)
+
+// AccumulateRewards credits the coinbase of the given block with the mining
+// reward. The total reward consists of the static block reward and rewards for
+// included uncles. The coinbase of each uncle block is also rewarded.
+func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
+ // Select the correct block reward based on chain progression
+ var blockReward = big.NewInt(FrontierBlockReward.Int64())
+
+ //blockReward := FrontierBlockReward
+ if config.IsByzantium(header.Number) {
+ blockReward = ByzantiumBlockReward
+ }
+ if config.IsConstantinople(header.Number) {
+ blockReward = ConstantinopleBlockReward
+ }
+ if config.IsWorldland(header.Number) {
+ blockReward = big.NewInt(WorldLandBlockReward.Int64())
+
+ if config.IsWorldLandHalving(header.Number) {
+ blockHeight := header.Number.Uint64()
+ HalvingLevel := (blockHeight - 1 - config.WorldlandBlock.Uint64()) / HALVING_INTERVAL
+
+ blockReward.Rsh(blockReward, uint(HalvingLevel))
+
+ } else if config.IsWorldLandMaturity(header.Number) {
+ blockHeight := header.Number.Uint64()
+ blockReward = big.NewInt(1e+18)
+
+ MaturityLevel := (blockHeight - 1 - config.HalvingEndTime.Uint64()) / MATURITY_INTERVAL
+
+ blockReward.Mul(blockReward, SumRewardUntilMaturity)
+ blockReward.Div(blockReward, new(big.Int).SetUint64(MATURITY_INTERVAL))
+
+ blockReward.Mul(blockReward, big.NewInt(4))
+ blockReward.Div(blockReward, big.NewInt(100))
+
+ for i := 0; i < int(MaturityLevel); i++ {
+ blockReward.Mul(blockReward, big.NewInt(104))
+ blockReward.Div(blockReward, big.NewInt(100))
+ }
+ }
+ }
+
+ // Accumulate the rewards for the miner and any included uncles
+ reward := new(big.Int).Set(blockReward)
+ r := new(big.Int)
+ for _, uncle := range uncles {
+ r.Add(uncle.Number, big8)
+ r.Sub(r, header.Number)
+ r.Mul(r, blockReward)
+ r.Div(r, big8)
+ state.AddBalance(uncle.Coinbase, r)
+
+ r.Div(blockReward, big32)
+ reward.Add(reward, r)
+ }
+ state.AddBalance(header.Coinbase, reward)
+}
diff --git a/consensus/kaiju/consensus_test.go b/consensus/kaiju/consensus_test.go
new file mode 100644
index 000000000000..38e4184e4a8d
--- /dev/null
+++ b/consensus/kaiju/consensus_test.go
@@ -0,0 +1,393 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package kaiju
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "testing"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/common/math"
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+type diffTest struct {
+ ParentTimestamp uint64
+ ParentDifficulty *big.Int
+ CurrentTimestamp uint64
+ CurrentBlocknumber *big.Int
+ CurrentDifficulty *big.Int
+}
+
+func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
+ var ext struct {
+ ParentTimestamp string
+ ParentDifficulty string
+ CurrentTimestamp string
+ CurrentBlocknumber string
+ CurrentDifficulty string
+ }
+ if err := json.Unmarshal(b, &ext); err != nil {
+ return err
+ }
+
+ d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp)
+ d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty)
+ d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
+ d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber)
+ d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty)
+
+ return nil
+}
+
+func TestDecodingVerification(t *testing.T) {
+ for i := 0; i < 8; i++ {
+ ecc := ECC{}
+ header := new(types.Header)
+ header.Difficulty = ProbToDifficulty(Table[0].miningProb)
+ hash := ecc.SealHash(header).Bytes()
+
+ _, hashVector, outputWord, LDPCNonce, digest := RunOptimizedConcurrencyLDPC(header, hash)
+
+ headerForTest := types.CopyHeader(header)
+ headerForTest.MixDigest = common.BytesToHash(digest)
+ headerForTest.Nonce = types.EncodeNonce(LDPCNonce)
+ hashForTest := ecc.SealHash(headerForTest).Bytes()
+
+ flag, hashVectorOfVerification, outputWordOfVerification, digestForValidation := VerifyOptimizedDecoding(headerForTest, hashForTest)
+
+ encodedDigestForValidation := common.BytesToHash(digestForValidation)
+
+ //fmt.Printf("%+v\n", header)
+ //fmt.Printf("Hash : %v\n", hash)
+ //fmt.Println()
+
+ //fmt.Printf("%+v\n", headerForTest)
+ //fmt.Printf("headerForTest : %v\n", headerForTest)
+ //fmt.Println()
+
+ // * means padding for compare easily
+ if flag && bytes.Equal(headerForTest.MixDigest[:], encodedDigestForValidation[:]) {
+ fmt.Printf("Hash vector ** ************ : %v\n", hashVector)
+ fmt.Printf("Hash vector of verification : %v\n", hashVectorOfVerification)
+
+ fmt.Printf("Outputword ** ************ : %v\n", outputWord)
+ fmt.Printf("Outputword of verification : %v\n", outputWordOfVerification)
+
+ fmt.Printf("LDPC Nonce : %v\n", LDPCNonce)
+ fmt.Printf("Digest : %v\n", headerForTest.MixDigest[:])
+ /*
+ t.Logf("Hash vector : %v\n", hashVector)
+ t.Logf("Outputword : %v\n", outputWord)
+ t.Logf("LDPC Nonce : %v\n", LDPCNonce)
+ t.Logf("Digest : %v\n", header.MixDigest[:])
+ */
+ } else {
+ fmt.Printf("Hash vector ** ************ : %v\n", hashVector)
+ fmt.Printf("Hash vector of verification : %v\n", hashVectorOfVerification)
+
+ fmt.Printf("Outputword ** ************ : %v\n", outputWord)
+ fmt.Printf("Outputword of verification : %v\n", outputWordOfVerification)
+
+ fmt.Printf("flag : %v\n", flag)
+ fmt.Printf("Digest compare result : %v\n", bytes.Equal(headerForTest.MixDigest[:], encodedDigestForValidation[:]))
+ fmt.Printf("Digest *** ********** : %v\n", headerForTest.MixDigest[:])
+ fmt.Printf("Digest for validation : %v\n", encodedDigestForValidation)
+
+ t.Errorf("Test Fail")
+ /*
+ t.Errorf("flag : %v\n", flag)
+ t.Errorf("Digest compare result : %v", bytes.Equal(header.MixDigest[:], digestForValidation)
+ t.Errorf("Digest : %v\n", digest)
+ t.Errorf("Digest for validation : %v\n", digestForValidation)
+ */
+ }
+ //t.Logf("\n")
+ fmt.Println()
+ }
+}
+
+// TestVRFProofWithoutProof tests that blocks without VRF proof are rejected
+func TestVRFProofWithoutProof(t *testing.T) {
+ ecc := &ECC{}
+ header := &types.Header{
+ Number: big.NewInt(1),
+ Difficulty: big.NewInt(1000),
+ Time: 1234567890,
+ }
+
+ err := ecc.verifyVRFProof(header)
+ if err == nil {
+ t.Fatal("Expected error for header without VRF proof")
+ }
+ if err.Error() != "VRF proof is required but missing" {
+ t.Errorf("Expected 'VRF proof is required but missing', got '%s'", err.Error())
+ }
+}
+
+// TestVRFProofWithoutPublicKey tests that blocks without VRF public key are rejected
+func TestVRFProofWithoutPublicKey(t *testing.T) {
+ ecc := &ECC{}
+ header := &types.Header{
+ Number: big.NewInt(1),
+ Difficulty: big.NewInt(1000),
+ Time: 1234567890,
+ VRFProof: []byte("dummy_proof"),
+ }
+
+ err := ecc.verifyVRFProof(header)
+ if err == nil {
+ t.Fatal("Expected error for VRF proof without public key")
+ }
+ if err.Error() != "VRF public key is required but missing" {
+ t.Errorf("Expected 'VRF public key is required but missing', got '%s'", err.Error())
+ }
+}
+
+// TestVRFProofInvalid tests that blocks with invalid VRF proofs are rejected
+func TestVRFProofInvalid(t *testing.T) {
+ ecc := &ECC{}
+ pk, _ := KeyGen()
+
+ header := &types.Header{
+ Number: big.NewInt(1),
+ Difficulty: big.NewInt(1000),
+ Time: 1234567890,
+ VRFProof: []byte("invalid_proof_data"),
+ VRFPublicKey: pk,
+ }
+
+ err := ecc.verifyVRFProof(header)
+ if err == nil {
+ t.Fatal("Expected error for invalid VRF proof")
+ }
+}
+
+// TestVRFProofMismatchedKey tests that blocks with mismatched key and proof are rejected
+func TestVRFProofMismatchedKey(t *testing.T) {
+ ecc := &ECC{}
+ pk1, sk1 := KeyGen()
+ pk2, _ := KeyGen()
+
+ message := []byte("test message")
+ pi, _, err := Prove(pk1, sk1, message)
+ if err != nil {
+ t.Fatalf("Failed to generate VRF proof: %v", err)
+ }
+
+ header := &types.Header{
+ Number: big.NewInt(1),
+ Difficulty: big.NewInt(1000),
+ Time: 1234567890,
+ VRFProof: pi,
+ VRFPublicKey: pk2,
+ }
+
+ err = ecc.verifyVRFProof(header)
+ if err == nil {
+ t.Fatal("Expected error for mismatched key and proof")
+ }
+}
+
+// TestVRFProofSortition tests that blocks are accepted or rejected based on sortition
+func TestVRFProofSortition(t *testing.T) {
+ ecc := &ECC{}
+ numTests := 10
+ passCount := 0
+
+ for i := 0; i < numTests; i++ {
+ pk, sk := KeyGen()
+ message := ecc.SealHash(&types.Header{
+ Number: big.NewInt(int64(i + 1)),
+ Difficulty: big.NewInt(1000),
+ Time: uint64(1234567890 + i),
+ }).Bytes()
+
+ pi, _, err := Prove(pk, sk, message)
+ if err != nil {
+ t.Fatalf("Failed to generate VRF proof: %v", err)
+ }
+
+ header := &types.Header{
+ Number: big.NewInt(int64(i + 1)),
+ Difficulty: big.NewInt(1000),
+ Time: uint64(1234567890 + i),
+ VRFProof: pi,
+ VRFPublicKey: pk,
+ }
+
+ err = ecc.verifyVRFProof(header)
+ passedSortition := CheckSortition(pi)
+
+ if passedSortition {
+ if err != nil {
+ t.Errorf("Block %d: valid VRF proof passing sortition was rejected: %v", i, err)
+ } else {
+ passCount++
+ }
+ } else {
+ if err == nil {
+ t.Errorf("Block %d: VRF proof failing sortition was accepted", i)
+ }
+ }
+ }
+}
+
+// TestVRFProofDeterministic tests that VRF verification is deterministic
+func TestVRFProofDeterministic(t *testing.T) {
+ ecc := &ECC{}
+ pk, sk := KeyGen()
+ message := []byte("deterministic test")
+ pi, _, err := Prove(pk, sk, message)
+ if err != nil {
+ t.Fatalf("Failed to generate VRF proof: %v", err)
+ }
+
+ header := &types.Header{
+ Number: big.NewInt(100),
+ Difficulty: big.NewInt(1000),
+ Time: 1234567890,
+ VRFProof: pi,
+ VRFPublicKey: pk,
+ }
+
+ firstErr := ecc.verifyVRFProof(header)
+ for i := 0; i < 20; i++ {
+ err := ecc.verifyVRFProof(header)
+ if (firstErr == nil) != (err == nil) {
+ t.Fatalf("Verification not deterministic: first=%v, iteration %d=%v", firstErr, i, err)
+ }
+ if firstErr != nil && err != nil && firstErr.Error() != err.Error() {
+ t.Fatalf("Error message changed: first=%v, iteration %d=%v", firstErr, i, err)
+ }
+ }
+}
+
+// TestVRFProofCorrectSubmission tests that blocks with valid VRF proofs passing sortition are accepted
+func TestVRFProofCorrectSubmission(t *testing.T) {
+ ecc := &ECC{}
+
+ maxAttempts := 10
+ accepted := false
+
+ for attempt := 0; attempt < maxAttempts; attempt++ {
+ pk, sk := KeyGen()
+ message := ecc.SealHash(&types.Header{
+ Number: big.NewInt(int64(attempt + 1)),
+ Difficulty: big.NewInt(1000),
+ Time: uint64(1234567890 + attempt),
+ }).Bytes()
+
+ pi, hash, err := Prove(pk, sk, message)
+ if err != nil {
+ t.Fatalf("Failed to generate VRF proof: %v", err)
+ }
+
+ // Check if this proof passes sortition
+ if !CheckSortition(pi) {
+ continue
+ }
+
+ // Found a proof that passes sortition, now verify it's accepted
+ header := &types.Header{
+ Number: big.NewInt(int64(attempt + 1)),
+ Difficulty: big.NewInt(1000),
+ Time: uint64(1234567890 + attempt),
+ VRFProof: pi,
+ VRFPublicKey: pk,
+ }
+
+ err = ecc.verifyVRFProof(header)
+ if err != nil {
+ t.Fatalf("Valid VRF proof passing sortition was rejected: %v", err)
+ }
+
+ // Verify the proof cryptographically
+ valid, err := Verify(pk, pi, message)
+ if err != nil {
+ t.Fatalf("VRF verification failed: %v", err)
+ }
+ if !valid {
+ t.Fatal("VRF proof verification returned false")
+ }
+
+ t.Logf("✓ Correct VRF proof accepted (attempt %d)", attempt+1)
+ t.Logf(" VRF output: %x", hash)
+ t.Logf(" Sortition: PASSED")
+ accepted = true
+ break
+ }
+
+ if !accepted {
+ t.Fatalf("Failed to generate a proof passing sortition after %d attempts", maxAttempts)
+ }
+}
+
+// TestVRFProofMultipleValid tests multiple valid VRF proofs are accepted when they pass sortition
+func TestVRFProofMultipleValid(t *testing.T) {
+ ecc := &ECC{}
+
+ // Generate multiple valid proofs
+ validCount := 0
+ maxTests := 50
+ targetValid := 3 // Try to get at least 3 valid proofs
+
+ for i := 0; i < maxTests && validCount < targetValid; i++ {
+ pk, sk := KeyGen()
+ message := ecc.SealHash(&types.Header{
+ Number: big.NewInt(int64(i + 1)),
+ Difficulty: big.NewInt(1000),
+ Time: uint64(1234567890 + i),
+ }).Bytes()
+
+ pi, hash, err := Prove(pk, sk, message)
+ if err != nil {
+ t.Fatalf("Failed to generate VRF proof: %v", err)
+ }
+
+ // Only test proofs that pass sortition
+ if !CheckSortition(pi) {
+ continue
+ }
+
+ header := &types.Header{
+ Number: big.NewInt(int64(i + 1)),
+ Difficulty: big.NewInt(1000),
+ Time: uint64(1234567890 + i),
+ VRFProof: pi,
+ VRFPublicKey: pk,
+ }
+
+ err = ecc.verifyVRFProof(header)
+ if err != nil {
+ t.Errorf("Block %d: valid VRF proof was rejected: %v", i, err)
+ continue
+ }
+
+ validCount++
+ t.Logf("✓ Block %d: VRF proof accepted, output=%x", i, hash[:8])
+ }
+
+ if validCount == 0 {
+ t.Fatalf("No valid proofs passed sortition in %d attempts", maxTests)
+ }
+
+ t.Logf("\n=== Summary: %d/%d blocks with valid VRF proofs were accepted ===", validCount, maxTests)
+}
diff --git a/consensus/kaiju/sealer.go b/consensus/kaiju/sealer.go
new file mode 100644
index 000000000000..bb707f9b1846
--- /dev/null
+++ b/consensus/kaiju/sealer.go
@@ -0,0 +1,725 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package kaiju
+
+import (
+ "bytes"
+ "context"
+ crand "crypto/rand"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math"
+ "math/big"
+ "math/rand"
+ "net/http"
+ "runtime"
+ "sync"
+ "time"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/common/hexutil"
+ "github.com/cryptoecc/WorldLand/consensus"
+ "github.com/cryptoecc/WorldLand/core/types"
+ "github.com/cryptoecc/WorldLand/crypto"
+ "github.com/cryptoecc/WorldLand/log"
+)
+
+const (
+ // staleThreshold is the maximum depth of the acceptable stale but valid ecc solution.
+ staleThreshold = 7
+)
+
+var (
+ errNoMiningWork = errors.New("no mining work available yet")
+ errInvalidSealResult = errors.New("invalid or stale proof-of-work solution")
+)
+
+// Seal implements consensus.Engine, attempting to find a nonce that satisfies
+// the block's difficulty requirements.
+func (ecc *ECC) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
+ // If we're running a fake PoW, simply return a 0 nonce immediately
+ if ecc.config.PowMode == ModeFake || ecc.config.PowMode == ModeFullFake {
+ header := block.Header()
+ header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{}
+ select {
+ case results <- block.WithSeal(header):
+ default:
+ log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ecc.SealHash(block.Header()))
+ }
+ return nil
+ }
+ // If we're running a shared PoW, delegate sealing to it
+ if ecc.shared != nil {
+ return ecc.shared.Seal(chain, block, results, stop)
+ }
+
+ // Check sortition epoch eligibility before starting to mine
+ blockNumber := block.Header().Number.Uint64()
+ sortitionEpoch := SortitionEpoch(blockNumber)
+
+ eligible, sortitionProof, err := ecc.IsEligibleForSortitionEpoch(chain, blockNumber)
+ if err != nil {
+ log.Warn("❌ Failed to check sortition eligibility", "sortitionEpoch", sortitionEpoch, "block", blockNumber, "err", err)
+ return fmt.Errorf("sortition eligibility check failed: %w", err)
+ }
+
+ if !eligible {
+ log.Warn("❌ Not eligible to mine in this sortition epoch - sortition failed",
+ "sortitionEpoch", sortitionEpoch,
+ "block", blockNumber,
+ "seedBlock", GetSortitionSeedBlockNumber(blockNumber))
+ return errors.New("not eligible for sortition epoch")
+ }
+
+ log.Info("✅ Eligible to mine in this sortition epoch",
+ "sortitionEpoch", sortitionEpoch,
+ "block", blockNumber,
+ "proofLen", len(sortitionProof))
+
+ // Store the sortition proof in the header for verification by other nodes
+ header := block.Header()
+ header.VRFProof = sortitionProof
+ ecc.lock.Lock()
+ header.VRFPublicKey = ecc.vrfPublicKey
+ ecc.lock.Unlock()
+
+ // Create a new block with the VRF fields set
+ // This ensures the mining functions receive a block with VRF proof and public key
+ block = block.WithSeal(header)
+
+ // Create a runner and the multiple search threads it directs
+ abort := make(chan struct{})
+
+ ecc.lock.Lock()
+ threads := ecc.threads
+ if ecc.rand == nil {
+ seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
+ if err != nil {
+ ecc.lock.Unlock()
+ return err
+ }
+ ecc.rand = rand.New(rand.NewSource(seed.Int64()))
+ }
+ ecc.lock.Unlock()
+ if threads == 0 {
+ threads = runtime.NumCPU()
+ }
+ if threads < 0 {
+ threads = 0 // Allows disabling local mining without extra logic around local/remote
+ }
+ // Push new work to remote sealer
+ if ecc.remote != nil {
+ ecc.remote.workCh <- &sealTask{block: block, results: results}
+ }
+ var (
+ pend sync.WaitGroup
+ locals = make(chan *types.Block)
+ )
+
+ for i := 0; i < threads; i++ {
+ pend.Add(1)
+ go func(id int, nonce uint64) {
+ defer pend.Done()
+ //ecc.mine(block, id, nonce, abort, locals)
+ if chain.Config().IsMio(block.Header().Number) {
+ ecc.mine_mio(block, id, nonce, abort, locals)
+ } else if chain.Config().IsSeoul(block.Header().Number) {
+ ecc.mine_seoul(block, id, nonce, abort, locals)
+ } else {
+ ecc.mine(block, id, nonce, abort, locals)
+ }
+ }(i, uint64(ecc.rand.Int63()))
+ }
+
+ // Wait until sealing is terminated or a nonce is found
+ go func() {
+ var result *types.Block
+ select {
+ case <-stop:
+ // Outside abort, stop all miner threads
+ close(abort)
+ case result = <-locals:
+ // One of the threads found a block, abort all others
+ select {
+ case results <- result:
+ default:
+ ecc.config.Log.Warn("Sealing result is not read by miner", "mode", "local", "sealhash", ecc.SealHash(block.Header()))
+ }
+ close(abort)
+ case <-ecc.update:
+ // Thread count was changed on user request, restart
+ close(abort)
+ if err := ecc.Seal(chain, block, results, stop); err != nil {
+ ecc.config.Log.Error("Failed to restart sealing after update", "err", err)
+ }
+ }
+ // Wait for all miners to terminate and return the block
+ pend.Wait()
+ }()
+
+ return nil
+}
+
+// mine is the actual proof-of-work miner that searches for a nonce starting from
+// seed that results in correct final block difficulty.
+func (ecc *ECC) mine(block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block) {
+ // Extract some data from the header
+ var (
+ header = block.Header()
+ hash = ecc.SealHash(header).Bytes()
+ )
+ // Start generating random nonces until we abort or find a good one
+ var (
+ total_attempts = int64(0)
+ attempts = int64(0)
+ nonce = seed
+ )
+ logger := log.New("miner", id)
+ logger.Trace("Started ecc search for new nonces", "seed", seed)
+search:
+ for {
+ select {
+ case <-abort:
+ // Mining terminated, update stats and abort
+ logger.Trace("ecc nonce search aborted", "attempts", nonce-seed)
+ ecc.hashrate.Mark(attempts)
+ break search
+
+ default:
+ // We don't have to update hash rate on every nonce, so update after after 2^X nonces
+ total_attempts = total_attempts + 64
+ attempts = attempts + 64
+ if (attempts % (1 << 15)) == 0 {
+ ecc.hashrate.Mark(attempts)
+ attempts = 0
+ }
+ // Compute the PoW value of this nonce
+
+ flag, _, outputWord, LDPCNonce, digest := RunOptimizedConcurrencyLDPC(header, hash)
+
+ // Correct nonce found, create a new header with it
+ if flag == true {
+ //level := SearchLevel_Seoul(header.Difficulty)
+ //fmt.Printf("level: %v\n", level)
+ //fmt.Printf("total attempts: %v\n", total_attempts)
+ //fmt.Printf("hashrate: %v\n", ecc.Hashrate())
+ //fmt.Printf("Codeword found with nonce = %d\n", LDPCNonce)
+ //fmt.Printf("Codeword : %d\n", outputWord)
+
+ header = types.CopyHeader(header)
+ header.MixDigest = common.BytesToHash(digest)
+ header.Nonce = types.EncodeNonce(LDPCNonce)
+
+ //convert codeword
+ var codeword []byte
+ var codeVal byte
+ for i, v := range outputWord {
+ codeVal |= byte(v) << (7 - i%8)
+ if i%8 == 7 {
+ codeword = append(codeword, codeVal)
+ codeVal = 0
+ }
+ }
+ if len(outputWord)%8 != 0 {
+ codeword = append(codeword, codeVal)
+ }
+ header.Codeword = make([]byte, len(codeword))
+ copy(header.Codeword, codeword)
+ //fmt.Printf("header: %v\n", header)
+ //fmt.Printf("header Codeword : %v\n", header.Codeword)
+
+ // Seal and return a block (if still needed)
+ select {
+ case found <- block.WithSeal(header):
+ logger.Trace("ecc nonce found and reported", "LDPCNonce", LDPCNonce)
+ case <-abort:
+ logger.Trace("ecc nonce found but discarded", "LDPCNonce", LDPCNonce)
+ }
+ break search
+ }
+ }
+ }
+}
+
+func (ecc *ECC) mine_seoul(block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block) {
+ // Extract some data from the header
+ var (
+ header = block.Header()
+ hash = ecc.SealHash(header).Bytes()
+ )
+ // Start generating random nonces until we abort or find a good one
+ var (
+ total_attempts = int64(0)
+ attempts = int64(0)
+ nonce = seed
+ )
+ logger := log.New("miner", id)
+ logger.Trace("Started ecc search for new nonces", "seed", seed)
+
+ parameters, _ := setParameters_Seoul(header)
+ //fmt.Println(parameters)
+ H := generateH(parameters)
+ colInRow, rowInCol := generateQ(parameters, H)
+
+search:
+ for {
+ select {
+ case <-abort:
+ // Mining terminated, update stats and abort
+ logger.Trace("ecc nonce search aborted", "attempts", nonce-seed)
+ ecc.hashrate.Mark(attempts)
+ break search
+
+ default:
+ // We don't have to update hash rate on every nonce, so update after after 2^X nonces
+ total_attempts = total_attempts + 1
+ attempts = attempts + 1
+ if (attempts % (1 << 15)) == 0 {
+ ecc.hashrate.Mark(attempts)
+ attempts = 0
+ }
+
+ digest := make([]byte, 40)
+ copy(digest, hash)
+ binary.LittleEndian.PutUint64(digest[32:], nonce)
+ digest = crypto.Keccak512(digest)
+ //fmt.Printf("nonce: %v\n", digest)
+
+ goRoutineHashVector := generateHv(parameters, digest)
+ goRoutineHashVector, goRoutineOutputWord, _ := OptimizedDecodingSeoul(parameters, goRoutineHashVector, H, rowInCol, colInRow)
+
+ flag, _ := MakeDecision_Seoul(header, colInRow, goRoutineOutputWord)
+ //fmt.Printf("nonce: %v\n", nonce)
+ //fmt.Printf("nonce: %v\n", weight)
+
+ if flag == true {
+ //hashVector := goRoutineHashVector
+ outputWord := goRoutineOutputWord
+
+ //level := SearchLevel_Seoul(header.Difficulty)
+ /*fmt.Printf("level: %v\n", level)
+ fmt.Printf("total attempts: %v\n", total_attempts)
+ fmt.Printf("hashrate: %v\n", ecc.Hashrate())
+ fmt.Printf("Codeword found with nonce = %d\n", nonce)
+ fmt.Printf("Codeword : %d\n", outputWord)*/
+
+ header = types.CopyHeader(header)
+ header.CodeLength = uint64(parameters.n)
+ header.MixDigest = common.BytesToHash(digest)
+ header.Nonce = types.EncodeNonce(nonce)
+
+ //convert codeword
+ var codeword []byte
+ var codeVal byte
+ for i, v := range outputWord {
+ codeVal |= byte(v) << (7 - i%8)
+ if i%8 == 7 {
+ codeword = append(codeword, codeVal)
+ codeVal = 0
+ }
+ }
+ if len(outputWord)%8 != 0 {
+ codeword = append(codeword, codeVal)
+ }
+ header.Codeword = make([]byte, len(codeword))
+ copy(header.Codeword, codeword)
+ //fmt.Printf("header: %v\n", header)
+ //fmt.Printf("header Codeword : %v\n", header.Codeword)
+
+ // Seal and return a block (if still needed)
+ select {
+ case found <- block.WithSeal(header):
+ logger.Trace("ecc nonce found and reported", "LDPCNonce", nonce)
+ case <-abort:
+ logger.Trace("ecc nonce found but discarded", "LDPCNonce", nonce)
+ }
+ break search
+ }
+ nonce++
+ }
+ }
+}
+
+func (ecc *ECC) mine_mio(block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block) {
+ // Extract some data from the header
+ var (
+ header = block.Header()
+ hash = ecc.SealHash(header).Bytes()
+ )
+ // Start generating random nonces until we abort or find a good one
+ var (
+ total_attempts = int64(0)
+ attempts = int64(0)
+ nonce = seed
+ )
+ logger := log.New("miner", id)
+ logger.Trace("Started ecc search for new nonces", "seed", seed)
+
+ parameters, _ := setParameters_Seoul(header)
+ //fmt.Println(parameters)
+ H := generateH(parameters)
+ colInRow, rowInCol := generateQ(parameters, H)
+
+search:
+ for {
+ select {
+ case <-abort:
+ // Mining terminated, update stats and abort
+ logger.Trace("ecc nonce search aborted", "attempts", nonce-seed)
+ ecc.hashrate.Mark(attempts)
+ break search
+
+ default:
+ // We don't have to update hash rate on every nonce, so update after after 2^X nonces
+ total_attempts = total_attempts + 1
+ attempts = attempts + 1
+ if (attempts % (1 << 15)) == 0 {
+ ecc.hashrate.Mark(attempts)
+ attempts = 0
+ }
+
+ digest := make([]byte, 40)
+ copy(digest, hash)
+ binary.LittleEndian.PutUint64(digest[32:], nonce)
+ digest = crypto.Keccak512(digest)
+ //fmt.Printf("nonce: %v\n", digest)
+
+ goRoutineHashVector := generateHv(parameters, digest)
+ goRoutineHashVector, goRoutineOutputWord, _ := OptimizedDecodingSeoul(parameters, goRoutineHashVector, H, rowInCol, colInRow)
+
+ flag, _ := MakeDecision_Seoul(header, colInRow, goRoutineOutputWord)
+ //fmt.Printf("nonce: %v\n", nonce)
+ //fmt.Printf("nonce: %v\n", weight)
+
+ if flag == true {
+ //hashVector := goRoutineHashVector
+ outputWord := goRoutineOutputWord
+
+ //level := SearchLevel_Seoul(header.Difficulty)
+ /*fmt.Printf("level: %v\n", level)
+ fmt.Printf("total attempts: %v\n", total_attempts)
+ fmt.Printf("hashrate: %v\n", ecc.Hashrate())
+ fmt.Printf("Codeword found with nonce = %d\n", nonce)
+ fmt.Printf("Codeword : %d\n", outputWord)*/
+
+ header = types.CopyHeader(header)
+ header.CodeLength = uint64(parameters.n)
+ header.MixDigest = common.BytesToHash(digest)
+ header.Nonce = types.EncodeNonce(nonce)
+
+ //convert codeword
+ var codeword []byte
+ var codeVal byte
+ for i, v := range outputWord {
+ codeVal |= byte(v) << (7 - i%8)
+ if i%8 == 7 {
+ codeword = append(codeword, codeVal)
+ codeVal = 0
+ }
+ }
+ if len(outputWord)%8 != 0 {
+ codeword = append(codeword, codeVal)
+ }
+ header.Codeword = make([]byte, len(codeword))
+ copy(header.Codeword, codeword)
+ //fmt.Printf("header: %v\n", header)
+ //fmt.Printf("header Codeword : %v\n", header.Codeword)
+
+ // VRF proof and sortition were already checked at Seal() entry point
+ // The header already has VRFProof and VRFPublicKey set from epoch sortition
+ // Just seal the block with the valid PoW nonce
+ logger.Info("✅ PoW solution found, sealing block", "block", header.Number, "nonce", nonce)
+
+ // Seal and return a block (if still needed)
+ select {
+ case found <- block.WithSeal(header):
+ logger.Trace("ecc nonce found and reported", "LDPCNonce", nonce)
+ case <-abort:
+ logger.Trace("ecc nonce found but discarded", "LDPCNonce", nonce)
+ }
+ break search
+ }
+ nonce++
+ }
+ }
+}
+
+// GPU MINING... NEED TO UPDTAE
+// This is the timeout for HTTP requests to notify external miners.
+const remoteSealerTimeout = 1 * time.Second
+
+type remoteSealer struct {
+ works map[common.Hash]*types.Block
+ rates map[common.Hash]hashrate
+ currentBlock *types.Block
+ currentWork [4]string
+ notifyCtx context.Context
+ cancelNotify context.CancelFunc // cancels all notification requests
+ reqWG sync.WaitGroup // tracks notification request goroutines
+
+ ecc *ECC
+ noverify bool
+ notifyURLs []string
+ results chan<- *types.Block
+ workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer
+ fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work
+ submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result
+ fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
+ submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate
+ requestExit chan struct{}
+ exitCh chan struct{}
+}
+
+// sealTask wraps a seal block with relative result channel for remote sealer thread.
+type sealTask struct {
+ block *types.Block
+ results chan<- *types.Block
+}
+
+// mineResult wraps the pow solution parameters for the specified block.
+type mineResult struct {
+ nonce types.BlockNonce
+ mixDigest common.Hash
+ hash common.Hash
+
+ errc chan error
+}
+
+// hashrate wraps the hash rate submitted by the remote sealer.
+type hashrate struct {
+ id common.Hash
+ ping time.Time
+ rate uint64
+
+ done chan struct{}
+}
+
+// sealWork wraps a seal work package for remote sealer.
+type sealWork struct {
+ errc chan error
+ res chan [4]string
+}
+
+func startRemoteSealer(ecc *ECC, urls []string, noverify bool) *remoteSealer {
+ ctx, cancel := context.WithCancel(context.Background())
+ s := &remoteSealer{
+ ecc: ecc,
+ noverify: noverify,
+ notifyURLs: urls,
+ notifyCtx: ctx,
+ cancelNotify: cancel,
+ works: make(map[common.Hash]*types.Block),
+ rates: make(map[common.Hash]hashrate),
+ workCh: make(chan *sealTask),
+ fetchWorkCh: make(chan *sealWork),
+ submitWorkCh: make(chan *mineResult),
+ fetchRateCh: make(chan chan uint64),
+ submitRateCh: make(chan *hashrate),
+ requestExit: make(chan struct{}),
+ exitCh: make(chan struct{}),
+ }
+ go s.loop()
+ return s
+}
+
+func (s *remoteSealer) loop() {
+ defer func() {
+ s.ecc.config.Log.Trace("ECC remote sealer is exiting")
+ s.cancelNotify()
+ s.reqWG.Wait()
+ close(s.exitCh)
+ }()
+
+ ticker := time.NewTicker(5 * time.Second)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case work := <-s.workCh:
+ // Update current work with new received block.
+ // Note same work can be past twice, happens when changing CPU threads.
+ s.results = work.results
+ s.makeWork(work.block)
+ s.notifyWork()
+
+ case work := <-s.fetchWorkCh:
+ // Return current mining work to remote miner.
+ if s.currentBlock == nil {
+ work.errc <- errNoMiningWork
+ } else {
+ work.res <- s.currentWork
+ }
+
+ case result := <-s.submitWorkCh:
+ // Verify submitted PoW solution based on maintained mining blocks.
+ if s.submitWork(result.nonce, result.mixDigest, result.hash) {
+ result.errc <- nil
+ } else {
+ result.errc <- errInvalidSealResult
+ }
+
+ case result := <-s.submitRateCh:
+ // Trace remote sealer's hash rate by submitted value.
+ s.rates[result.id] = hashrate{rate: result.rate, ping: time.Now()}
+ close(result.done)
+
+ case req := <-s.fetchRateCh:
+ // Gather all hash rate submitted by remote sealer.
+ var total uint64
+ for _, rate := range s.rates {
+ // this could overflow
+ total += rate.rate
+ }
+ req <- total
+
+ case <-ticker.C:
+ // Clear stale submitted hash rate.
+ for id, rate := range s.rates {
+ if time.Since(rate.ping) > 10*time.Second {
+ delete(s.rates, id)
+ }
+ }
+ // Clear stale pending blocks
+ if s.currentBlock != nil {
+ for hash, block := range s.works {
+ if block.NumberU64()+staleThreshold <= s.currentBlock.NumberU64() {
+ delete(s.works, hash)
+ }
+ }
+ }
+
+ case <-s.requestExit:
+ return
+ }
+ }
+}
+
+// makeWork creates a work package for external miner.
+//
+// The work package consists of 3 strings:
+//
+// result[0], 32 bytes hex encoded current block header pow-hash
+// result[1], 32 bytes hex encoded seed hash used for DAG
+// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
+// result[3], hex encoded block number
+func (s *remoteSealer) makeWork(block *types.Block) {
+ hash := s.ecc.SealHash(block.Header())
+ s.currentWork[0] = hash.Hex()
+ s.currentWork[1] = common.BytesToHash(SeedHash(block.NumberU64())).Hex()
+ s.currentWork[2] = common.BytesToHash(new(big.Int).Div(two256, block.Difficulty()).Bytes()).Hex()
+ s.currentWork[3] = hexutil.EncodeBig(block.Number())
+
+ // Trace the seal work fetched by remote sealer.
+ s.currentBlock = block
+ s.works[hash] = block
+}
+
+// notifyWork notifies all the specified mining endpoints of the availability of
+// new work to be processed.
+func (s *remoteSealer) notifyWork() {
+ work := s.currentWork
+
+ // Encode the JSON payload of the notification. When NotifyFull is set,
+ // this is the complete block header, otherwise it is a JSON array.
+ var blob []byte
+ if s.ecc.config.NotifyFull {
+ blob, _ = json.Marshal(s.currentBlock.Header())
+ } else {
+ blob, _ = json.Marshal(work)
+ }
+
+ s.reqWG.Add(len(s.notifyURLs))
+ for _, url := range s.notifyURLs {
+ go s.sendNotification(s.notifyCtx, url, blob, work)
+ }
+}
+
+func (s *remoteSealer) sendNotification(ctx context.Context, url string, json []byte, work [4]string) {
+ defer s.reqWG.Done()
+
+ req, err := http.NewRequest("POST", url, bytes.NewReader(json))
+ if err != nil {
+ s.ecc.config.Log.Warn("Can't create remote miner notification", "err", err)
+ return
+ }
+ ctx, cancel := context.WithTimeout(ctx, remoteSealerTimeout)
+ defer cancel()
+ req = req.WithContext(ctx)
+ req.Header.Set("Content-Type", "application/json")
+
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ s.ecc.config.Log.Warn("Failed to notify remote miner", "err", err)
+ } else {
+ s.ecc.config.Log.Trace("Notified remote miner", "miner", url, "hash", work[0], "target", work[2])
+ resp.Body.Close()
+ }
+}
+
+// submitWork verifies the submitted pow solution, returning
+// whether the solution was accepted or not (not can be both a bad pow as well as
+// any other error, like no pending work or stale mining result).
+func (s *remoteSealer) submitWork(nonce types.BlockNonce, mixDigest common.Hash, sealhash common.Hash) bool {
+ if s.currentBlock == nil {
+ s.ecc.config.Log.Error("Pending work without block", "sealhash", sealhash)
+ return false
+ }
+ // Make sure the work submitted is present
+ block := s.works[sealhash]
+ if block == nil {
+ s.ecc.config.Log.Warn("Work submitted but none pending", "sealhash", sealhash, "curnumber", s.currentBlock.NumberU64())
+ return false
+ }
+ // Verify the correctness of submitted result.
+ header := block.Header()
+ header.Nonce = nonce
+ header.MixDigest = mixDigest
+
+ start := time.Now()
+ if !s.noverify {
+ if err := s.ecc.verifySeal(nil, header); err != nil {
+ s.ecc.config.Log.Warn("Invalid proof-of-work submitted", "sealhash", sealhash, "elapsed", common.PrettyDuration(time.Since(start)), "err", err)
+ return false
+ }
+ }
+ // Make sure the result channel is assigned.
+ if s.results == nil {
+ s.ecc.config.Log.Warn("Eccresult channel is empty, submitted mining result is rejected")
+ return false
+ }
+ s.ecc.config.Log.Trace("Verified correct proof-of-work", "sealhash", sealhash, "elapsed", common.PrettyDuration(time.Since(start)))
+
+ // Solutions seems to be valid, return to the miner and notify acceptance.
+ solution := block.WithSeal(header)
+
+ // The submitted solution is within the scope of acceptance.
+ if solution.NumberU64()+staleThreshold > s.currentBlock.NumberU64() {
+ select {
+ case s.results <- solution:
+ s.ecc.config.Log.Debug("Work submitted is acceptable", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash())
+ return true
+ default:
+ s.ecc.config.Log.Warn("Sealing result is not read by miner", "mode", "remote", "sealhash", sealhash)
+ return false
+ }
+ }
+ // The submitted block is too old to accept, drop it.
+ s.ecc.config.Log.Warn("Work submitted is too old", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash())
+ return false
+}
diff --git a/consensus/kaiju/sealer_test.go b/consensus/kaiju/sealer_test.go
new file mode 100644
index 000000000000..c3152fb84953
--- /dev/null
+++ b/consensus/kaiju/sealer_test.go
@@ -0,0 +1,214 @@
+package kaiju
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "math/big"
+ "net"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/cryptoecc/WorldLand/common"
+ "github.com/cryptoecc/WorldLand/core/types"
+)
+
+// Tests whether remote HTTP servers are correctly notified of new work.
+func TestRemoteNotify(t *testing.T) {
+ // Start a simple webserver to capture notifications
+ sink := make(chan [3]string)
+
+ server := &http.Server{
+ Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ blob, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ t.Fatalf("failed to read miner notification: %v", err)
+ }
+ var work [3]string
+ if err := json.Unmarshal(blob, &work); err != nil {
+ t.Fatalf("failed to unmarshal miner notification: %v", err)
+ }
+ sink <- work
+ }),
+ }
+ // Open a custom listener to extract its local address
+ listener, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatalf("failed to open notification server: %v", err)
+ }
+ defer listener.Close()
+
+ go server.Serve(listener)
+
+ // Wait for server to start listening
+ var tries int
+ for tries = 0; tries < 10; tries++ {
+ conn, _ := net.DialTimeout("tcp", listener.Addr().String(), 1*time.Second)
+ if conn != nil {
+ break
+ }
+ }
+ if tries == 10 {
+ t.Fatal("tcp listener not ready for more than 10 seconds")
+ }
+
+ // Create the custom ecc engine
+ ecc := NewTester([]string{"http://" + listener.Addr().String()}, false)
+ defer ecc.Close()
+
+ // Stream a work task and ensure the notification bubbles out
+ header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)}
+ block := types.NewBlockWithHeader(header)
+
+ ecc.Seal(nil, block, nil, nil)
+ select {
+ case work := <-sink:
+ if want := ecc.SealHash(header).Hex(); work[0] != want {
+ t.Errorf("work packet hash mismatch: have %s, want %s", work[0], want)
+ }
+ //if want := common.BytesToHash(SeedHash(header.Number.Uint64())).Hex(); work[1] != want {
+ if want := header.ParentHash.Hex(); work[1] != want {
+ t.Errorf("work packet seed mismatch: have %s, want %s", work[1], want)
+ }
+ //target := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), 256), header.Difficulty)
+ //if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want {
+ // t.Errorf("work packet target mismatch: have %s, want %s", work[2], want)
+ //}
+ case <-time.After(3 * time.Second):
+ t.Fatalf("notification timed out")
+ }
+}
+
+// Tests that pushing work packages fast to the miner doesn't cause any data race
+// issues in the notifications.
+func TestRemoteMultiNotify(t *testing.T) {
+ // Start a simple webserver to capture notifications
+ sink := make(chan [3]string, 64)
+
+ server := &http.Server{
+ Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ blob, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ t.Fatalf("failed to read miner notification: %v", err)
+ }
+ var work [3]string
+ if err := json.Unmarshal(blob, &work); err != nil {
+ t.Fatalf("failed to unmarshal miner notification: %v", err)
+ }
+ sink <- work
+ }),
+ }
+ // Open a custom listener to extract its local address
+ listener, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatalf("failed to open notification server: %v", err)
+ }
+ defer listener.Close()
+
+ go server.Serve(listener)
+
+ // Create the custom ecc engine
+ ecc := NewTester([]string{"http://" + listener.Addr().String()}, false)
+ defer ecc.Close()
+
+ // Stream a lot of work task and ensure all the notifications bubble out
+ for i := 0; i < cap(sink); i++ {
+ header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)}
+ block := types.NewBlockWithHeader(header)
+
+ ecc.Seal(nil, block, nil, nil)
+ }
+ /*
+ for i := 0; i < cap(sink); i++ {
+ select {
+ case <-sink:
+ case <-time.After(3 * time.Second):
+ t.Fatalf("notification %d timed out", i)
+ }
+ }
+ */
+}
+
+// Tests whether stale solutions are correctly processed.
+func TestStaleSubmission(t *testing.T) {
+ ecc := NewTester(nil, true)
+ defer ecc.Close()
+ api := &API{ecc}
+
+ fakeNonce, fakeDigest := types.BlockNonce{0x01, 0x02, 0x03}, common.HexToHash("deadbeef")
+
+ testcases := []struct {
+ headers []*types.Header
+ submitIndex int
+ submitRes bool
+ }{
+ // Case1: submit solution for the latest mining package
+ {
+ []*types.Header{
+ {ParentHash: common.BytesToHash([]byte{0xa}), Number: big.NewInt(1), Difficulty: big.NewInt(100000000)},
+ },
+ 0,
+ true,
+ },
+ // Case2: submit solution for the previous package but have same parent.
+ {
+ []*types.Header{
+ {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000000)},
+ {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000001)},
+ },
+ 0,
+ true,
+ },
+ // Case3: submit stale but acceptable solution
+ {
+ []*types.Header{
+ {ParentHash: common.BytesToHash([]byte{0xc}), Number: big.NewInt(3), Difficulty: big.NewInt(100000000)},
+ {ParentHash: common.BytesToHash([]byte{0xd}), Number: big.NewInt(9), Difficulty: big.NewInt(100000000)},
+ },
+ 0,
+ true,
+ },
+ // Case4: submit very old solution
+ {
+ []*types.Header{
+ {ParentHash: common.BytesToHash([]byte{0xe}), Number: big.NewInt(10), Difficulty: big.NewInt(100000000)},
+ {ParentHash: common.BytesToHash([]byte{0xf}), Number: big.NewInt(17), Difficulty: big.NewInt(100000000)},
+ },
+ 0,
+ false,
+ },
+ }
+ results := make(chan *types.Block, 16)
+
+ for id, c := range testcases {
+ for _, h := range c.headers {
+ ecc.Seal(nil, types.NewBlockWithHeader(h), results, nil)
+ }
+ if res := api.SubmitWork(fakeNonce, ecc.SealHash(c.headers[c.submitIndex]), fakeDigest); res != c.submitRes {
+ t.Errorf("case %d submit result mismatch, want %t, get %t", id+1, c.submitRes, res)
+ }
+ if !c.submitRes {
+ continue
+ }
+ select {
+ case res := <-results:
+ if res.Header().Nonce != fakeNonce {
+ t.Errorf("case %d block nonce mismatch, want %s, get %s", id+1, fakeNonce, res.Header().Nonce)
+ }
+ if res.Header().MixDigest != fakeDigest {
+ t.Errorf("case %d block digest mismatch, want %s, get %s", id+1, fakeDigest, res.Header().MixDigest)
+ }
+ if res.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() {
+ t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Header().Difficulty)
+ }
+ if res.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() {
+ t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Header().Number.Uint64())
+ }
+ if res.Header().ParentHash != c.headers[c.submitIndex].ParentHash {
+ t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Header().ParentHash.Hex())
+ }
+ case <-time.NewTimer(time.Second).C:
+ t.Errorf("case %d fetch ecc result timeout", id+1)
+ }
+ }
+}
diff --git a/consensus/kaiju/vct_ed25519.go b/consensus/kaiju/vct_ed25519.go
new file mode 100644
index 000000000000..b56de7a7a90a
--- /dev/null
+++ b/consensus/kaiju/vct_ed25519.go
@@ -0,0 +1,388 @@
+package kaiju
+
+import (
+ "bytes"
+ "crypto/ed25519"
+ "crypto/rand"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/yoseplee/vrf/edwards25519"
+)
+
+const (
+ limit = 100 // hashToCurve 시도 횟수 제한
+ N2 = 32 // 정수 크기 (256bit)
+ N = N2 / 2 // N은 16바이트
+ qs = "1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed" // q = 2^252 + ...
+ cofactor = 8 // Edwards25519 곱셈 계수
+ NOSIGN = 3 // sign 없음 (for hashToCurve)
+)
+
+var (
+ ErrMalformedInput = errors.New("ECVRF: malformed input")
+ ErrDecodeError = errors.New("ECVRF: decode error")
+ ErrInternalError = errors.New("ECVRF: internal error")
+ q, _ = new(big.Int).SetString(qs, 16) // 커브 차수 q
+ g = ge() // 기본점 g = B (Base point)
+)
+
+const (
+ // PublicKeySize is the size, in bytes, of public keys as used in this package.
+ PublicKeySize = 32
+ // PrivateKeySize is the size, in bytes, of private keys as used in this package.
+ PrivateKeySize = 64
+ // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+ SignatureSize = 64
+)
+
+// assume were generated by ed25519.GenerateKey()
+// Prove generates vrf output and corresponding proof(pi) with secret key
+// Prove: VRF 증명(pi)과 해시(hash)를 생성
+func Prove(pk []byte, sk []byte, m []byte) (pi, hash []byte, err error) {
+ x := expandSecret(sk) // 비밀키를 확장하여 스칼라 x로 사용
+ h := hashToCurve(m, pk) // 메시지를 커브 상의 점 h로 해싱
+ r := ecp2OS(geScalarMult(h, x)) // gamma = h^x
+
+ // 랜덤 nonce k 생성
+ kp, ks, err := ed25519.GenerateKey(nil)
+ if err != nil {
+ return nil, nil, err
+ }
+ k := expandSecret(ks)
+
+ // c = H(g, h, pk, gamma, g^k, h^k)
+ c := hashPoints(
+ ecp2OS(g),
+ ecp2OS(h),
+ s2OS(pk),
+ r,
+ s2OS(kp),
+ ecp2OS(geScalarMult(h, k)),
+ )
+
+ // s = k - c*x mod q
+ var z big.Int
+ s := z.Mod(z.Sub(f2IP(k), z.Mul(c, f2IP(x))), q)
+
+ // 증명 pi = gamma || c || s
+ var buf bytes.Buffer
+ buf.Write(r)
+ buf.Write(i2OSP(c, N))
+ buf.Write(i2OSP(s, N2))
+ pi = buf.Bytes()
+
+ return pi, Hash(pi), nil
+}
+
+// Hash: pi에서 VRF output만 추출
+func Hash(pi []byte) []byte {
+ return pi[1 : N2+1] // 첫 바이트는 sign
+}
+
+// Verify: pi가 유효한지 확인
+func Verify(pk []byte, pi []byte, m []byte) (bool, error) {
+ r, c, s, err := decodeProof(pi)
+ if err != nil {
+ return false, err
+ }
+
+ // u = pk^c * g^s
+ var u edwards25519.ProjectiveGroupElement
+ P := os2ECP(pk, pk[31]>>7)
+ if P == nil {
+ return false, ErrMalformedInput
+ }
+ edwards25519.GeDoubleScalarMultVartime(&u, c, P, s)
+
+ // v = gamma^c * h^s
+ h := hashToCurve(m, pk)
+ v := geAdd(geScalarMult(r, c), geScalarMult(h, s))
+
+ // c' = H(g, h, pk, gamma, u, v)
+ c2 := hashPoints(
+ ecp2OS(g),
+ ecp2OS(h),
+ s2OS(pk),
+ ecp2OS(r),
+ ecp2OSProj(&u),
+ ecp2OS(v),
+ )
+
+ return c2.Cmp(f2IP(c)) == 0, nil
+}
+
+func decodeProof(pi []byte) (r *edwards25519.ExtendedGroupElement, c *[N2]byte, s *[N2]byte, err error) {
+ // sign bit
+ sign := pi[0]
+ if sign != 2 && sign != 3 {
+ return nil, nil, nil, ErrDecodeError
+ }
+
+ // r = gamma
+ r = os2ECP(pi[1:1+N2], sign-2)
+ if r == nil {
+ return nil, nil, nil, ErrDecodeError
+ }
+
+ // c 추출 (N 바이트)
+ c = new([N2]byte)
+ for j := N - 1; j >= 0; j-- {
+ c[j] = pi[1+N2+(N-1-j)]
+ }
+
+ // s 추출 (N2 바이트)
+ s = new([N2]byte)
+ for j := N2 - 1; j >= 0; j-- {
+ s[j] = pi[1+N2+N+(N2-1-j)]
+ }
+ return
+}
+
+func hashPoints(ps ...[]byte) *big.Int {
+ h := sha256.New()
+ // fmt.Printf("hash_points:\n")
+ for _, p := range ps {
+ h.Write(p)
+ // fmt.Printf("%s\n", hex.Dump(p))
+ }
+ v := h.Sum(nil)
+ return os2IP(v[:N])
+}
+
+// 메시지를 커브 점으로 변환하는 함수
+func hashToCurve(m []byte, pk []byte) *edwards25519.ExtendedGroupElement {
+ hash := sha256.New()
+ for i := int64(0); i < limit; i++ {
+ ctr := i2OSP(big.NewInt(i), 4)
+ hash.Write(m)
+ hash.Write(pk)
+ hash.Write(ctr)
+ h := hash.Sum(nil)
+ hash.Reset()
+ if P := os2ECP(h, NOSIGN); P != nil {
+ for j := 1; j < cofactor; j *= 2 {
+ P = geDouble(P) // cofactor 제거
+ }
+ return P
+ }
+ }
+ panic("hashToCurve: couldn't make a point on curve")
+}
+
+func os2ECP(os []byte, sign byte) *edwards25519.ExtendedGroupElement {
+ P := new(edwards25519.ExtendedGroupElement)
+ var buf [32]byte
+ copy(buf[:], os)
+ if sign == 0 || sign == 1 {
+ buf[31] = (sign << 7) | (buf[31] & 0x7f)
+ }
+ if !P.FromBytes(&buf) {
+ return nil
+ }
+ return P
+}
+
+// just prepend the sign octet
+func s2OS(s []byte) []byte {
+ sign := s[31] >> 7 // @@ we should clear the sign bit??
+ os := []byte{sign + 2} // Y = 0x02 if positive or 0x03 if negative
+ os = append([]byte(os), s...)
+ return os
+}
+
+func ecp2OS(P *edwards25519.ExtendedGroupElement) []byte {
+ var s [32]byte
+ P.ToBytes(&s)
+ return s2OS(s[:])
+}
+
+func ecp2OSProj(P *edwards25519.ProjectiveGroupElement) []byte {
+ var s [32]byte
+ P.ToBytes(&s)
+ return s2OS(s[:])
+}
+
+func i2OSP(b *big.Int, n int) []byte {
+ os := b.Bytes()
+ if n > len(os) {
+ var buf bytes.Buffer
+ buf.Write(make([]byte, n-len(os))) // prepend 0s
+ buf.Write(os)
+ return buf.Bytes()
+ } else {
+ return os[:n]
+ }
+}
+
+func os2IP(os []byte) *big.Int {
+ return new(big.Int).SetBytes(os)
+}
+
+// convert a field number (in LittleEndian) to a big int
+func f2IP(f *[32]byte) *big.Int {
+ var t [32]byte
+ for i := 0; i < 32; i++ {
+ t[32-i-1] = f[i]
+ }
+ return os2IP(t[:])
+}
+
+func ip2F(b *big.Int) *[32]byte {
+ os := b.Bytes()
+ r := new([32]byte)
+ j := len(os) - 1
+ for i := 0; i < 32 && j >= 0; i++ {
+ r[i] = os[j]
+ j--
+ }
+ return r
+}
+
+func ge() *edwards25519.ExtendedGroupElement {
+ g := new(edwards25519.ExtendedGroupElement)
+ var f edwards25519.FieldElement
+ edwards25519.FeOne(&f)
+ var s [32]byte
+ edwards25519.FeToBytes(&s, &f)
+ edwards25519.GeScalarMultBase(g, &s) // g = g^1
+ return g
+}
+
+func expandSecret(sk []byte) *[32]byte {
+ // copied from golang.org/x/crypto/ed25519/ed25519.go -- has to be the same
+ digest := sha512.Sum512(sk[:32])
+ digest[0] &= 248
+ digest[31] &= 127
+ digest[31] |= 64
+ h := new([32]byte)
+ copy(h[:], digest[:])
+ return h
+}
+
+// copied from edwards25519.go and const.go in golang.org/x/crypto/ed25519/internal/edwards25519
+type CachedGroupElement struct {
+ yPlusX, yMinusX, Z, T2d edwards25519.FieldElement
+}
+
+// d2 is 2*d.
+var d2 = edwards25519.FieldElement{
+ -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199,
+}
+
+func toCached(r *CachedGroupElement, p *edwards25519.ExtendedGroupElement) {
+ edwards25519.FeAdd(&r.yPlusX, &p.Y, &p.X)
+ edwards25519.FeSub(&r.yMinusX, &p.Y, &p.X)
+ edwards25519.FeCopy(&r.Z, &p.Z)
+ edwards25519.FeMul(&r.T2d, &p.T, &d2)
+}
+
+func geAdd(p, qe *edwards25519.ExtendedGroupElement) *edwards25519.ExtendedGroupElement {
+ var q CachedGroupElement
+ var r edwards25519.CompletedGroupElement
+ var t0 edwards25519.FieldElement
+
+ toCached(&q, qe)
+
+ edwards25519.FeAdd(&r.X, &p.Y, &p.X)
+ edwards25519.FeSub(&r.Y, &p.Y, &p.X)
+ edwards25519.FeMul(&r.Z, &r.X, &q.yPlusX)
+ edwards25519.FeMul(&r.Y, &r.Y, &q.yMinusX)
+ edwards25519.FeMul(&r.T, &q.T2d, &p.T)
+ edwards25519.FeMul(&r.X, &p.Z, &q.Z)
+ edwards25519.FeAdd(&t0, &r.X, &r.X)
+ edwards25519.FeSub(&r.X, &r.Z, &r.Y)
+ edwards25519.FeAdd(&r.Y, &r.Z, &r.Y)
+ edwards25519.FeAdd(&r.Z, &t0, &r.T)
+ edwards25519.FeSub(&r.T, &t0, &r.T)
+
+ re := new(edwards25519.ExtendedGroupElement)
+ r.ToExtended(re)
+ return re
+}
+
+func geDouble(p *edwards25519.ExtendedGroupElement) *edwards25519.ExtendedGroupElement {
+ var q edwards25519.ProjectiveGroupElement
+ p.ToProjective(&q)
+ var rc edwards25519.CompletedGroupElement
+ q.Double(&rc)
+ r := new(edwards25519.ExtendedGroupElement)
+ rc.ToExtended(r)
+ return r
+}
+
+func extendedGroupElementCMove(t, u *edwards25519.ExtendedGroupElement, b int32) {
+ edwards25519.FeCMove(&t.X, &u.X, b)
+ edwards25519.FeCMove(&t.Y, &u.Y, b)
+ edwards25519.FeCMove(&t.Z, &u.Z, b)
+ edwards25519.FeCMove(&t.T, &u.T, b)
+}
+
+func geScalarMult(h *edwards25519.ExtendedGroupElement, a *[32]byte) *edwards25519.ExtendedGroupElement {
+ q := new(edwards25519.ExtendedGroupElement)
+ q.Zero()
+ p := h
+ for i := uint(0); i < 256; i++ {
+ bit := int32(a[i>>3]>>(i&7)) & 1
+ t := geAdd(q, p)
+ extendedGroupElementCMove(q, t, bit)
+ p = geDouble(p)
+ }
+ return q
+}
+
+// Prove + Verify 수행 후 결과 출력
+func DoTestECVRF(pk, sk []byte, msg []byte, verbose bool) string {
+ pi, _, _ := Prove(pk, sk, msg[:])
+ res, _ := Verify(pk, pi, msg[:])
+ if !res {
+ fmt.Println("Verify failed")
+ }
+ if verbose {
+ fmt.Printf("message: %s\n", hex.EncodeToString(msg))
+ fmt.Printf("sk: %s\n", hex.EncodeToString(sk))
+ fmt.Printf("pk: %s\n", hex.EncodeToString(pk))
+ fmt.Printf("pi: %s\n", hex.EncodeToString(pi))
+ fmt.Printf("randomNumber: %s\n", hex.EncodeToString(Hash(pi)))
+ fmt.Printf("Verification: %t\n", res)
+ }
+ return hex.EncodeToString(Hash(pi))
+}
+
+// Sortition checks if the random number passes the sortition criteria
+func Sortition(RN string) bool {
+ if len(RN) == 0 {
+ return false
+ }
+ firstChar := RN[0]
+
+ return (firstChar >= '0' && firstChar <= '9')
+}
+
+// CheckSortition checks if a VRF proof passes the sortition criteria
+// Returns true if the node is selected to produce a block
+func CheckSortition(vrfProof []byte) bool {
+ hash := Hash(vrfProof)
+ randomNumber := hex.EncodeToString(hash)
+ return Sortition(randomNumber)
+}
+
+// 노드를 무작위 선택 (sortition 아님)
+func runEccpow(arr []int) {
+ length := len(arr)
+ nBig, err := rand.Int(rand.Reader, big.NewInt(int64(length)))
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("Node %d is selected.\n", arr[nBig.Int64()])
+}
+
+// ed25519 키쌍 생성
+func KeyGen() ([]byte, []byte) {
+ pk, sk, _ := ed25519.GenerateKey(nil)
+ return pk, sk
+}
diff --git a/consensus/kaiju/vct_test.go b/consensus/kaiju/vct_test.go
new file mode 100644
index 000000000000..bb21b1e777e4
--- /dev/null
+++ b/consensus/kaiju/vct_test.go
@@ -0,0 +1,183 @@
+package kaiju
+
+import (
+ "encoding/hex"
+ "fmt"
+
+ // "reflect"
+ "testing"
+ "time"
+)
+
+func VCTtest(howmany int, message string, probability uint8, verbose bool) ([]int, time.Duration) {
+ var msg []byte
+ msg = []byte(message)
+ nodeSet := make([]Nodes, howmany)
+ winVCT := []int{}
+ nthreshold := Prob[(probability/5)-1].norm_bound
+
+ totalTime := time.Now()
+ for i := 0; i < howmany; i++ {
+ nodeSet[i] = PerformFalconVCT(i, msg, nthreshold)
+ if nodeSet[i].VCT_res {
+ winVCT = append(winVCT, i)
+ }
+ }
+ totalElapsedTime := time.Since(totalTime)
+ avgElapsedTime := totalElapsedTime / time.Duration(howmany)
+
+ fmt.Println()
+
+ if verbose {
+ for i := 0; i < howmany; i++ {
+ var temp int = len(nodeSet[i].pi)
+ fmt.Println("------------------------------------------------------------------------------------------------------------------------")
+ fmt.Println("id : ", nodeSet[i].id)
+ fmt.Println("norm : ", nodeSet[i].norm)
+ fmt.Println("VCT result : ", nodeSet[i].VCT_res)
+ fmt.Println("proof : ", nodeSet[i].pi[:16], "......", nodeSet[i].pi[temp-9:])
+ fmt.Println("verify : ", nodeSet[i].vrfy_res)
+ fmt.Println("elapsed_time : ", nodeSet[i].exe_time)
+ fmt.Println("------------------------------------------------------------------------------------------------------------------------")
+ }
+ }
+ return winVCT, avgElapsedTime
+}
+
+// 같은 seed / 메시지 / 확률 -> 동일 결과
+// func TestDeterministicSingle(t *testing.T) {
+// msg := []byte("deterministic")
+// nth := Prob[1].norm_bound // 10%
+
+// seed := makeSeed(42)
+// n1 := PerformFalconVCT(0, msg, nth, seed)
+// n2 := PerformFalconVCT(0, msg, nth, seed)
+
+// // 실행시간 문자열만 제거 후 비교
+// n1.exe_time, n2.exe_time = "", ""
+// if !reflect.DeepEqual(n1, n2) {
+// t.Fatalf("non-deterministic: %+v != %+v", n1, n2)
+// }
+// }
+
+// func TestDeterministicBatch(t *testing.T) {
+// howmany := 5
+// seeds := make([][]byte, howmany)
+// for i := 0; i < howmany; i++ {
+// seeds[i] = makeSeed(uint64(100 + i))
+// }
+
+// win1, _ := VCTtest(howmany, "batch-test", 10, false, seeds)
+// win2, _ := VCTtest(howmany, "batch-test", 10, false, seeds)
+
+// if !reflect.DeepEqual(win1, win2) {
+// t.Fatalf("winner set differs: %v vs %v", win1, win2)
+// }
+// }
+
+func TestVct(t *testing.T) {
+ howmany := 10
+ message := "test message for VCT"
+ probability := uint8(20) // 10%
+ verbose := true
+
+ fmt.Printf("\n=== Running VCT Test with %d nodes ===\n", howmany)
+
+ winners, avgTime := VCTtest(howmany, message, probability, verbose)
+
+ fmt.Printf("\n=== Test Results ===\n")
+ fmt.Printf("Total nodes: %d\n", howmany)
+ fmt.Printf("Winners (VCT passed): %v\n", winners)
+ fmt.Printf("Number of winners: %d\n", len(winners))
+ fmt.Printf("Average execution time: %v\n", avgTime)
+
+ // Basic validation
+ if len(winners) < 0 || len(winners) > howmany {
+ t.Fatalf("Invalid number of winners: %d (should be between 0 and %d)", len(winners), howmany)
+ }
+
+ if avgTime <= 0 {
+ t.Fatalf("Invalid average time: %v", avgTime)
+ }
+
+ t.Logf("Test passed: %d/%d nodes passed VCT", len(winners), howmany)
+}
+
+// TestED25519VCT tests VCT using ED25519 (much faster than Falcon)
+func TestED25519VCT(t *testing.T) {
+ howmany := 10
+ message := []byte("test message for ED25519 VCT")
+ verbose := true
+
+ fmt.Printf("\n=== Running ED25519 VCT Test with %d nodes ===\n", howmany)
+
+ winners := []int{}
+ totalTime := time.Now()
+
+ for i := 0; i < howmany; i++ {
+ fmt.Printf("\n[Node %d] Starting ED25519 VCT...\n", i)
+
+ // Step 1: Generate key pair
+ fmt.Printf("[Node %d] Step 1: Generating ED25519 key pair...\n", i)
+ keyStart := time.Now()
+ pk, sk := KeyGen()
+ fmt.Printf("[Node %d] Key generation took: %v\n", i, time.Since(keyStart))
+
+ // Step 2: Generate proof
+ fmt.Printf("[Node %d] Step 2: Generating VRF proof...\n", i)
+ proveStart := time.Now()
+ pi, hash, err := Prove(pk, sk, message)
+ fmt.Printf("[Node %d] Proof generation took: %v\n", i, time.Since(proveStart))
+ if err != nil {
+ t.Fatalf("Node %d: Prove failed: %v", i, err)
+ }
+
+ // Step 3: Verify proof
+ fmt.Printf("[Node %d] Step 3: Verifying proof...\n", i)
+ verifyStart := time.Now()
+ valid, err := Verify(pk, pi, message)
+ fmt.Printf("[Node %d] Verification took: %v\n", i, time.Since(verifyStart))
+ if err != nil {
+ t.Fatalf("Node %d: Verify failed: %v", i, err)
+ }
+ if !valid {
+ t.Fatalf("Node %d: Verification returned false", i)
+ }
+ fmt.Printf("[Node %d] Verification result: SUCCESS\n", i)
+
+ // Step 4: Check VCT condition (sortition)
+ randomNumber := hex.EncodeToString(hash)
+ vctPassed := Sortition(randomNumber)
+
+ fmt.Printf("[Node %d] Step 4: VCT Check\n", i)
+ fmt.Printf("[Node %d] Random number: %s\n", i, randomNumber[:16]+"...")
+
+ if vctPassed {
+ winners = append(winners, i)
+ fmt.Printf("[Node %d] VCT CHECK PASSED ✓ (starts with 'a')\n", i)
+ } else {
+ fmt.Printf("[Node %d] VCT CHECK FAILED ✗ (doesn't start with 'a')\n", i)
+ }
+
+ if verbose && vctPassed {
+ fmt.Printf("[Node %d] Full random number: %s\n", i, randomNumber)
+ }
+ }
+
+ totalElapsedTime := time.Since(totalTime)
+ avgElapsedTime := totalElapsedTime / time.Duration(howmany)
+
+ fmt.Printf("\n=== Test Results ===\n")
+ fmt.Printf("Total nodes: %d\n", howmany)
+ fmt.Printf("Winners (VCT passed): %v\n", winners)
+ fmt.Printf("Number of winners: %d\n", len(winners))
+ fmt.Printf("Total time: %v\n", totalElapsedTime)
+ fmt.Printf("Average time per node: %v\n", avgElapsedTime)
+
+ // Validation
+ if len(winners) < 0 || len(winners) > howmany {
+ t.Fatalf("Invalid number of winners: %d", len(winners))
+ }
+
+ t.Logf("Test passed: %d/%d nodes passed VCT", len(winners), howmany)
+}
diff --git a/consensus/kaiju/vrf_keys.go b/consensus/kaiju/vrf_keys.go
new file mode 100644
index 000000000000..2d0a5f3e2770
--- /dev/null
+++ b/consensus/kaiju/vrf_keys.go
@@ -0,0 +1,51 @@
+package kaiju
+
+import (
+ "crypto/ed25519"
+ "crypto/sha512"
+
+ "github.com/cryptoecc/WorldLand/common"
+)
+
+// DeriveVRFKeys derives deterministic ED25519 VRF keys from the coinbase address
+// This allows the VRF keys to be derived from the miner's coinbase without additional key management
+// The nodeKey parameter can be a node's ECDSA private key bytes for additional entropy
+func DeriveVRFKeys(coinbase common.Address, nodeKey []byte) (publicKey, privateKey []byte, err error) {
+ // Combine coinbase address and node's private key (if available) to create seed
+ message := append([]byte("WorldLand VRF Key Derivation:"), coinbase.Bytes()...)
+ if len(nodeKey) > 0 {
+ message = append(message, nodeKey...)
+ }
+
+ // Hash to get seed
+ seed := sha512.Sum512(message)
+
+ // Generate ED25519 key from seed
+ reader := &deterministicReader{seed: seed[:]}
+ pub, priv, err := ed25519.GenerateKey(reader)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return pub, priv, nil
+}
+
+// deterministicReader is a deterministic random reader for key generation
+type deterministicReader struct {
+ seed []byte
+ index int
+}
+
+func (r *deterministicReader) Read(p []byte) (n int, err error) {
+ for i := range p {
+ if r.index >= len(r.seed) {
+ // Re-hash the seed if we need more randomness
+ hash := sha512.Sum512(r.seed)
+ r.seed = hash[:]
+ r.index = 0
+ }
+ p[i] = r.seed[r.index]
+ r.index++
+ }
+ return len(p), nil
+}
diff --git a/core/genesis.go b/core/genesis.go
index a7349a3e758d..cee469360430 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -440,6 +440,8 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
return params.SeoulChainConfig
case ghash == params.GwangjuGenesisHash:
return params.GwangjuChainConfig
+ case ghash == params.MioGenesisHash:
+ return params.MioChainConfig
default:
return params.AllEthashProtocolChanges
}
@@ -628,6 +630,23 @@ func DefaultGwangjuGenesisBlock() *Genesis {
}
}
+func DefaultMioGenesisBlock() *Genesis {
+ balanceStr := "40996800000000000000000000"
+ balance, _ := new(big.Int).SetString(balanceStr, 10)
+ return &Genesis{
+ Config: params.MioChainConfig,
+ Nonce: 10396,
+ Timestamp: 1767262724,
+ ExtraData: []byte("Worldland Mio"),
+ GasLimit: 30000000,
+ Difficulty: big.NewInt(1023),
+ Alloc: map[common.Address]GenesisAccount{
+ common.HexToAddress("0x8C98EAeA19F1B9B36af58e7d7E78e0F1df8138f0"): { Balance: balance },
+ },
+ }
+}
+
+
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *Genesis {
// Override the default period to the user requested one
diff --git a/core/types/block.go b/core/types/block.go
index 3a7469c92882..07946fb9e16e 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -85,11 +85,15 @@ type Header struct {
Nonce BlockNonce `json:"nonce"`
// BaseFee was added by EIP-1559 and is ignored in legacy headers.
- BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
+ BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
// Codeword was added by Worldlandhardfork and is ignored in legacy headers.
- Codeword []byte `json:"codeword" rlp:"optional"`
+ Codeword []byte `json:"codeword" rlp:"optional"`
// CodeLength was added by Worldlandhardfork and is ignored in legacy headers.
- CodeLength uint64 `json:"codelength" rlp:"optional"`
+ CodeLength uint64 `json:"codelength" rlp:"optional"`
+ // VRFProof was added for VRF verification and is ignored in legacy headers.
+ VRFProof []byte `json:"vrfProof" rlp:"optional"`
+ // VRFPublicKey was added for VRF verification and is ignored in legacy headers.
+ VRFPublicKey []byte `json:"vrfPublicKey" rlp:"optional"`
/*
TODO (MariusVanDerWijden) Add this field once needed
@@ -258,6 +262,14 @@ func CopyHeader(h *Header) *Header {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
}
+ if len(h.VRFProof) > 0 {
+ cpy.VRFProof = make([]byte, len(h.VRFProof))
+ copy(cpy.VRFProof, h.VRFProof)
+ }
+ if len(h.VRFPublicKey) > 0 {
+ cpy.VRFPublicKey = make([]byte, len(h.VRFPublicKey))
+ copy(cpy.VRFPublicKey, h.VRFPublicKey)
+ }
/*if len(h.Codeword) > 0 {
cpy.Codeword = make([]byte, len(h.Codeword))
copy(cpy.Codeword, h.Codeword)
@@ -321,17 +333,31 @@ func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
-func (b *Block) Codeword() []byte {
+func (b *Block) Codeword() []byte {
if b.header.Codeword == nil {
return nil
}
- return common.CopyBytes(b.header.Codeword)
+ return common.CopyBytes(b.header.Codeword)
}
-func (b *Block) CodeLength() uint64 {
+func (b *Block) CodeLength() uint64 {
return b.header.CodeLength
}
+func (b *Block) VRFProof() []byte {
+ if b.header.VRFProof == nil {
+ return nil
+ }
+ return common.CopyBytes(b.header.VRFProof)
+}
+
+func (b *Block) VRFPublicKey() []byte {
+ if b.header.VRFPublicKey == nil {
+ return nil
+ }
+ return common.CopyBytes(b.header.VRFPublicKey)
+}
+
func (b *Block) BaseFee() *big.Int {
if b.header.BaseFee == nil {
return nil
diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go
index a87cedf32695..aeecff396075 100644
--- a/core/types/gen_header_json.go
+++ b/core/types/gen_header_json.go
@@ -16,26 +16,27 @@ var _ = (*headerMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (h Header) MarshalJSON() ([]byte, error) {
type Header struct {
- ParentHash common.Hash `json:"parentHash" gencodec:"required"`
- UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
- Coinbase common.Address `json:"miner"`
- Root common.Hash `json:"stateRoot" gencodec:"required"`
- TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
- ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
- Bloom Bloom `json:"logsBloom" gencodec:"required"`
- Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
- Number *hexutil.Big `json:"number" gencodec:"required"`
- GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
- GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
- Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
- Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
- MixDigest common.Hash `json:"mixHash"`
- Nonce BlockNonce `json:"nonce"`
- BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
- Hash common.Hash `json:"hash"`
- Codeword hexutil.Bytes `json:"codeword" rlp:"optional"`
- CodeLength hexutil.Uint64 `json:"codelength" rlp:"optional"`
-
+ ParentHash common.Hash `json:"parentHash" gencodec:"required"`
+ UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
+ Coinbase common.Address `json:"miner"`
+ Root common.Hash `json:"stateRoot" gencodec:"required"`
+ TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
+ ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
+ Number *hexutil.Big `json:"number" gencodec:"required"`
+ GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
+ GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
+ Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
+ Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
+ MixDigest common.Hash `json:"mixHash"`
+ Nonce BlockNonce `json:"nonce"`
+ BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
+ Hash common.Hash `json:"hash"`
+ Codeword hexutil.Bytes `json:"codeword" rlp:"optional"`
+ CodeLength hexutil.Uint64 `json:"codelength" rlp:"optional"`
+ VRFProof hexutil.Bytes `json:"vrfProof" rlp:"optional"`
+ VRFPublicKey hexutil.Bytes `json:"vrfPublicKey" rlp:"optional"`
}
var enc Header
enc.ParentHash = h.ParentHash
@@ -57,30 +58,34 @@ func (h Header) MarshalJSON() ([]byte, error) {
enc.Hash = h.Hash()
enc.Codeword = h.Codeword
enc.CodeLength = hexutil.Uint64(h.CodeLength)
+ enc.VRFProof = h.VRFProof
+ enc.VRFPublicKey = h.VRFPublicKey
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (h *Header) UnmarshalJSON(input []byte) error {
type Header struct {
- ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
- UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
- Coinbase *common.Address `json:"miner"`
- Root *common.Hash `json:"stateRoot" gencodec:"required"`
- TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
- ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
- Bloom *Bloom `json:"logsBloom" gencodec:"required"`
- Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
- Number *hexutil.Big `json:"number" gencodec:"required"`
- GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
- GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
- Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
- Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
- MixDigest *common.Hash `json:"mixHash"`
- Nonce *BlockNonce `json:"nonce"`
- BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
- Codeword *hexutil.Bytes `json:"codeword" rlp:"optional"`
- CodeLength *hexutil.Uint64 `json:"codelength" rlp:"optional"`
+ ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
+ UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
+ Coinbase *common.Address `json:"miner"`
+ Root *common.Hash `json:"stateRoot" gencodec:"required"`
+ TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
+ ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
+ Bloom *Bloom `json:"logsBloom" gencodec:"required"`
+ Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
+ Number *hexutil.Big `json:"number" gencodec:"required"`
+ GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
+ GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
+ Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
+ Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
+ MixDigest *common.Hash `json:"mixHash"`
+ Nonce *BlockNonce `json:"nonce"`
+ BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
+ Codeword *hexutil.Bytes `json:"codeword" rlp:"optional"`
+ CodeLength *hexutil.Uint64 `json:"codelength" rlp:"optional"`
+ VRFProof *hexutil.Bytes `json:"vrfProof" rlp:"optional"`
+ VRFPublicKey *hexutil.Bytes `json:"vrfPublicKey" rlp:"optional"`
}
var dec Header
if err := json.Unmarshal(input, &dec); err != nil {
@@ -146,12 +151,18 @@ func (h *Header) UnmarshalJSON(input []byte) error {
if dec.BaseFee != nil {
h.BaseFee = (*big.Int)(dec.BaseFee)
}
- if dec.Codeword == nil {
+ if dec.Codeword != nil {
h.Codeword = *dec.Codeword
}
- if dec.CodeLength == nil {
+ if dec.CodeLength != nil {
h.CodeLength = uint64(*dec.CodeLength)
}
+ if dec.VRFProof != nil {
+ h.VRFProof = *dec.VRFProof
+ }
+ if dec.VRFPublicKey != nil {
+ h.VRFPublicKey = *dec.VRFPublicKey
+ }
return nil
}
diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go
index 13b14dab374f..2471b059deda 100644
--- a/core/types/gen_header_rlp.go
+++ b/core/types/gen_header_rlp.go
@@ -5,8 +5,11 @@
package types
-import "github.com/cryptoecc/WorldLand/rlp"
-import "io"
+import (
+ "io"
+
+ "github.com/cryptoecc/WorldLand/rlp"
+)
func (obj *Header) EncodeRLP(_w io.Writer) error {
w := rlp.NewEncoderBuffer(_w)
@@ -63,6 +66,22 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
if obj.CodeLength != 0 {
w.WriteUint64(obj.CodeLength)
}
+ _tmp3 := obj.VRFProof != nil
+ if _tmp3 {
+ if obj.VRFProof == nil {
+ w.Write(rlp.EmptyString)
+ } else {
+ w.WriteBytes(obj.VRFProof)
+ }
+ }
+ _tmp4 := obj.VRFPublicKey != nil
+ if _tmp4 {
+ if obj.VRFPublicKey == nil {
+ w.Write(rlp.EmptyString)
+ } else {
+ w.WriteBytes(obj.VRFPublicKey)
+ }
+ }
w.ListEnd(_tmp0)
return w.Flush()
}
diff --git a/eth/backend.go b/eth/backend.go
index 0211b009bd96..ae5437ec0ecc 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -31,6 +31,7 @@ import (
"github.com/cryptoecc/WorldLand/consensus"
"github.com/cryptoecc/WorldLand/consensus/beacon"
"github.com/cryptoecc/WorldLand/consensus/clique"
+ "github.com/cryptoecc/WorldLand/consensus/kaiju"
"github.com/cryptoecc/WorldLand/core"
"github.com/cryptoecc/WorldLand/core/bloombits"
"github.com/cryptoecc/WorldLand/core/rawdb"
@@ -138,21 +139,23 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
ethashConfig.NotifyFull = config.Miner.NotifyFull
eccpowConfig := config.Eccpow
+
+ kaijuConfig := config.Kaiju
/*
- eccpowConfig, err := core.LoadEccpowConfig(chainDb, config.Genesis)
- if err != nil {
- return nil, err
- }*/
+ eccpowConfig, err := core.LoadEccpowConfig(chainDb, config.Genesis)
+ if err != nil {
+ return nil, err
+ }*/
cliqueConfig, err := core.LoadCliqueConfig(chainDb, config.Genesis)
if err != nil {
return nil, err
}
-
- //engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, eccpowConfig, config.Miner.Notify, config.Miner.Noverify, chainDb)
- engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, &eccpowConfig, config.Miner.Notify, config.Miner.Noverify, chainDb)
+ //engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, eccpowConfig, config.Miner.Notify, config.Miner.Noverify, chainDb)
+ engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, &eccpowConfig, &kaijuConfig ,config.Miner.Notify, config.Miner.Noverify, chainDb)
+
eth := &Ethereum{
config: config,
merger: consensus.NewMerger(chainDb),
@@ -449,6 +452,40 @@ func (s *Ethereum) StartMining(threads int) error {
log.Error("Cannot start mining without etherbase", "err", err)
return fmt.Errorf("etherbase missing: %v", err)
}
+
+ // Setup VRF keys for sortition (if using kaiju consensus)
+ log.Info("Checking consensus engine type for VRF setup", "type", fmt.Sprintf("%T", s.engine))
+
+ // Try to get Kaiju engine (may be wrapped in Beacon)
+ var kaijuEngine *kaiju.ECC
+ if eccEngine, ok := s.engine.(*kaiju.ECC); ok {
+ kaijuEngine = eccEngine
+ } else if beaconEngine, ok := s.engine.(*beacon.Beacon); ok {
+ // Kaiju might be wrapped in Beacon, try to unwrap
+ innerEngine := beaconEngine.InnerEngine()
+ log.Info("Beacon engine detected, checking inner engine", "innerType", fmt.Sprintf("%T", innerEngine))
+
+ if innerEcc, ok := innerEngine.(*kaiju.ECC); ok {
+ kaijuEngine = innerEcc
+ log.Info("✅ Found Kaiju engine wrapped in Beacon")
+ } else {
+ log.Warn("Inner engine is not Kaiju", "innerType", fmt.Sprintf("%T", innerEngine))
+ }
+ }
+
+ if kaijuEngine != nil {
+ // Derive VRF keys from coinbase address
+ pubKey, privKey, err := kaiju.DeriveVRFKeys(eb, nil)
+ if err != nil {
+ log.Warn("Failed to derive VRF keys for sortition", "err", err)
+ } else {
+ kaijuEngine.SetVRFKeys(pubKey, privKey)
+ log.Info("✅ VRF keys configured for sortition", "coinbase", eb)
+ }
+ } else {
+ log.Info("Not using Kaiju consensus, skipping VRF setup", "engine", fmt.Sprintf("%T", s.engine))
+ }
+
var cli *clique.Clique
if c, ok := s.engine.(*clique.Clique); ok {
cli = c
diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go
index 7b195587559c..0d931566268b 100644
--- a/eth/ethconfig/config.go
+++ b/eth/ethconfig/config.go
@@ -31,6 +31,7 @@ import (
"github.com/cryptoecc/WorldLand/consensus/clique"
"github.com/cryptoecc/WorldLand/consensus/eccpow"
"github.com/cryptoecc/WorldLand/consensus/ethash"
+ "github.com/cryptoecc/WorldLand/consensus/kaiju"
"github.com/cryptoecc/WorldLand/core"
"github.com/cryptoecc/WorldLand/eth/downloader"
"github.com/cryptoecc/WorldLand/eth/gasprice"
@@ -185,6 +186,7 @@ type Config struct {
// Ethash options
Eccpow eccpow.Config
+ Kaiju kaiju.Config
// Transaction pool options
TxPool core.TxPoolConfig
@@ -222,11 +224,14 @@ type Config struct {
}
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
-func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, eccpowConfig *eccpow.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
+func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, eccpowConfig *eccpow.Config, kaijuConfig *kaiju.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
// If proof-of-authority is requested, set it up
var engine consensus.Engine
if cliqueConfig != nil {
engine = clique.New(cliqueConfig, db)
+ } else if kaijuConfig != nil {
+ engine = kaiju.New(kaiju.Config{}, notify, noverify)
+ log.Info("Creating Kaiju consensus engine")
} else if eccpowConfig != nil {
engine = eccpow.New(eccpow.Config{}, notify, noverify)
} else {
@@ -253,7 +258,7 @@ func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, clique
engine.(*ethash.Ethash).SetThreads(-1) // Disable CPU mining
}
//return engine , add worldland hardfork consensus.
-
+
//return beacon.New(engine, eccpow.New(eccpow.Config{}, nil, false))
return beacon.New(engine)
diff --git a/go.mod b/go.mod
index fb209643652f..fd8e402fe9b7 100644
--- a/go.mod
+++ b/go.mod
@@ -102,6 +102,7 @@ require (
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
+ github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b
golang.org/x/mod v0.8.0 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/protobuf v1.26.0 // indirect
diff --git a/go.sum b/go.sum
index 5864d461499c..0ffc432e76ca 100644
--- a/go.sum
+++ b/go.sum
@@ -41,6 +41,7 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
github.com/apilayer/freegeoip v3.5.0+incompatible h1:z1u2gv0/rsSi/HqMDB436AiUROXXim7st5DOg4Ikl4A=
github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go-v2 v1.2.0 h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c=
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
github.com/aws/aws-sdk-go-v2/config v1.1.1 h1:ZAoq32boMzcaTW9bcUacBswAmHTbvlvDJICgHFZuECo=
@@ -82,6 +83,10 @@ github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3h
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8=
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@@ -138,6 +143,7 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
+github.com/go-echarts/go-echarts v0.0.0-20190915064101-cbb3b43ade5d/go.mod h1:v4lFmU586g/A0xaH1RMDS86YlYrwpj8eHtR+xBReKE8=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
@@ -154,6 +160,11 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
+github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
+github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
+github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -218,6 +229,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
@@ -250,6 +262,7 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e h1:UvSe12bq+U
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@@ -261,6 +274,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4=
github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
+github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
@@ -268,6 +282,7 @@ github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM52
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -284,6 +299,7 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
@@ -303,6 +319,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
@@ -337,6 +355,7 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg=
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
@@ -364,9 +383,11 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -377,12 +398,17 @@ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -406,6 +432,7 @@ github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefld
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y=
github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
@@ -414,8 +441,12 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
+github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673/go.mod h1:Wq2sZrP++Us4tAw1h58MHS8BGIpC4NmKHfvw2QWBe9U=
+github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b h1:P+RO/IfYtPQHAm+8V8mwVsj6x0nwKR7/6nsWmyN3nYI=
+github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b/go.mod h1:KselA/fRyGFKpcu7sUBHPOz6Ji+7J9GzCKF/c6/ssbI=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -424,9 +455,11 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -520,12 +553,15 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -592,6 +628,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index b3ad7d17ea7f..f863bf98544b 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -731,10 +731,10 @@ func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) m
}
// GetBlockByNumber returns the requested canonical block.
-// * When blockNr is -1 the chain head is returned.
-// * When blockNr is -2 the pending chain head is returned.
-// * When fullTx is true all transactions in the block are returned, otherwise
-// only the transaction hash is returned.
+// - When blockNr is -1 the chain head is returned.
+// - When blockNr is -2 the pending chain head is returned.
+// - When fullTx is true all transactions in the block are returned, otherwise
+// only the transaction hash is returned.
func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.BlockByNumber(ctx, number)
if block != nil && err == nil {
@@ -1183,11 +1183,19 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
if head.Codeword != nil {
result["codeword"] = hexutil.Bytes(head.Codeword)
}
-
+
if head.CodeLength != 0 {
result["codelength"] = hexutil.Uint64(head.CodeLength)
}
+ if head.VRFProof != nil {
+ result["vrfProof"] = hexutil.Bytes(head.VRFProof)
+ }
+
+ if head.VRFPublicKey != nil {
+ result["vrfPublicKey"] = hexutil.Bytes(head.VRFPublicKey)
+ }
+
return result
}
diff --git a/les/client.go b/les/client.go
index 819f8a1010a0..4d55f51fa49d 100644
--- a/les/client.go
+++ b/les/client.go
@@ -128,7 +128,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
reqDist: newRequestDistributor(peers, &mclock.System{}),
accountManager: stack.AccountManager(),
merger: merger,
- engine: ethconfig.CreateConsensusEngine(stack, &config.Ethash, chainConfig.Clique, &config.Eccpow, nil, false, chainDb),
+ engine: ethconfig.CreateConsensusEngine(stack, &config.Ethash, chainConfig.Clique, &config.Eccpow, &config.Kaiju, nil, false, chainDb),
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
p2pServer: stack.Server(),
diff --git a/params/bootnodes.go b/params/bootnodes.go
index c67dc188955d..cae1e482e461 100644
--- a/params/bootnodes.go
+++ b/params/bootnodes.go
@@ -68,7 +68,6 @@ var RinkebyBootnodes = []string{
"enode://b6b28890b006743680c52e64e0d16db57f28124885595fa03a562be1d2bf0f3a1da297d56b13da25fb992888fd556d4c1a27b1f39d531bde7de1921c90061cc6@159.89.28.211:30303", // AKASHA
}
-
// SeoulBootnodes are the enode URLs of the P2P bootstrap nodes running on the
// Seoul network.
var SeoulBootnodes = []string{
@@ -98,6 +97,12 @@ var GwangjuBootnodes = []string{
"enode://911771c7894782bced03377a13f1d8a4e8450d05e03eabab1d6daae70e1b91b6074c346d42ac4fae53d98d273efedd6cdd37d2f6715302de9736b29cc4aa7da2@13.250.246.202:30303",
}
+// Mio Bootnodes are the enode URLs of the P2P bootstrap nodes running on the
+// Mio network.
+var MioBootnodes = []string{
+ "enode://a7ce7263293907cd317a24ba912bdd1302656d4c7e51260ea67ae159658214ea34a74dfbab647cd199a26b116a2c10be5c8ccbfb267d17449f74f088470e47a9@3.34.200.40:30303",
+}
+
// GoerliBootnodes are the enode URLs of the P2P bootstrap nodes running on the
// Görli test network.
var GoerliBootnodes = []string{
@@ -150,6 +155,8 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string {
switch genesis {
case GwangjuGenesisHash:
net = "gwangju"
+ case MioGenesisHash:
+ net = "mio"
case SeoulGenesisHash:
net = "seoul"
default:
diff --git a/params/config.go b/params/config.go
index e30eb5295a63..f7b6609dab89 100644
--- a/params/config.go
+++ b/params/config.go
@@ -34,8 +34,9 @@ var (
GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a")
KilnGenesisHash = common.HexToHash("0x51c7fe41be669f69c45c33a56982cbde405313342d9e2b00d7c91a7b284dd4f8")
- SeoulGenesisHash = common.HexToHash("0x5bd83be2a4c3a01b45e48fe181de1e6173d92cf5b54790fe64962dd2a7f25abb")
+ SeoulGenesisHash = common.HexToHash("0x5bd83be2a4c3a01b45e48fe181de1e6173d92cf5b54790fe64962dd2a7f25abb")
GwangjuGenesisHash = common.HexToHash("0x64130a2624d46bda6aacf0c1ec34ab3d926e31b8438141a10e7412070064f0bf")
+ MioGenesisHash = common.HexToHash("")
)
// TrustedCheckpoints associates each known checkpoint with the genesis hash of
@@ -277,34 +278,34 @@ var (
}
SeoulChainConfig = &ChainConfig{
- ChainID: big.NewInt(103),
- HomesteadBlock: big.NewInt(0),
- DAOForkBlock: nil,
- DAOForkSupport: true,
- EIP150Block: big.NewInt(0),
- EIP155Block: big.NewInt(0),
- EIP158Block: big.NewInt(0),
- ByzantiumBlock: big.NewInt(0),
- ConstantinopleBlock: big.NewInt(0),
- PetersburgBlock: big.NewInt(0),
- IstanbulBlock: big.NewInt(0),
- BerlinBlock: big.NewInt(0),
- LondonBlock: big.NewInt(0),
- WorldlandBlock: big.NewInt(0),
- SeoulBlock: big.NewInt(0),
- AnnapurnaBlock: big.NewInt(2_520_000),
- HalvingEndTime: big.NewInt(25228800),
- Eccpow: new(EccpowConfig),
- }
-
- /* SeoulTrustedCheckpoint contains the light client trusted checkpoint for the Seoul network.
+ ChainID: big.NewInt(103),
+ HomesteadBlock: big.NewInt(0),
+ DAOForkBlock: nil,
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ ByzantiumBlock: big.NewInt(0),
+ ConstantinopleBlock: big.NewInt(0),
+ PetersburgBlock: big.NewInt(0),
+ IstanbulBlock: big.NewInt(0),
+ BerlinBlock: big.NewInt(0),
+ LondonBlock: big.NewInt(0),
+ WorldlandBlock: big.NewInt(0),
+ SeoulBlock: big.NewInt(0),
+ AnnapurnaBlock: big.NewInt(2_520_000),
+ HalvingEndTime: big.NewInt(25228800),
+ Eccpow: new(EccpowConfig),
+ }
+
+ /* SeoulTrustedCheckpoint contains the light client trusted checkpoint for the Seoul network.
SeoulTrustedCheckpoint = &TrustedCheckpoint{
SectionIndex: 32,
SectionHead: common.HexToHash("0x50eaedd8361fa9edd0ac2dec410310b9bdf67b963b60f3b1dce47f84b30670f9"),
CHTRoot: common.HexToHash("0x6504db73139f75ffa9102ae980e41b361cf3d5b66cea06c79cde9f457368820c"),
BloomRoot: common.HexToHash("0x7551ae027bb776252a20ded51ee2ff0cbfbd1d8d57261b9161cc1f2f80237001"),
}
-
+
// SeoulCheckpointOracle contains a set of configs for the Seoul network oracle.
SeoulCheckpointOracle = &CheckpointOracleConfig{
Address: common.HexToAddress("0x18CA0E045F0D772a851BC7e48357Bcaab0a0795D"),
@@ -319,26 +320,48 @@ var (
}*/
GwangjuChainConfig = &ChainConfig{
- ChainID: big.NewInt(10395),
- HomesteadBlock: big.NewInt(0),
- DAOForkBlock: nil,
- DAOForkSupport: true,
- EIP150Block: big.NewInt(0),
- EIP155Block: big.NewInt(0),
- EIP158Block: big.NewInt(0),
- ByzantiumBlock: big.NewInt(0),
- ConstantinopleBlock: big.NewInt(0),
- PetersburgBlock: big.NewInt(0),
- IstanbulBlock: big.NewInt(0),
- BerlinBlock: big.NewInt(0),
- LondonBlock: big.NewInt(0),
- WorldlandBlock: big.NewInt(0),
- SeoulBlock: big.NewInt(0),
- AnnapurnaBlock: big.NewInt(2_194_400),
- HalvingEndTime: big.NewInt(25228800),
- Eccpow: new(EccpowConfig),
+ ChainID: big.NewInt(10395),
+ HomesteadBlock: big.NewInt(0),
+ DAOForkBlock: nil,
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ ByzantiumBlock: big.NewInt(0),
+ ConstantinopleBlock: big.NewInt(0),
+ PetersburgBlock: big.NewInt(0),
+ IstanbulBlock: big.NewInt(0),
+ BerlinBlock: big.NewInt(0),
+ LondonBlock: big.NewInt(0),
+ WorldlandBlock: big.NewInt(0),
+ SeoulBlock: big.NewInt(0),
+ AnnapurnaBlock: big.NewInt(2_194_400),
+ HalvingEndTime: big.NewInt(25228800),
+ Eccpow: new(EccpowConfig),
+ }
+
+ MioChainConfig = &ChainConfig{
+ ChainID: big.NewInt(10396),
+ HomesteadBlock: big.NewInt(0),
+ DAOForkBlock: nil,
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ ByzantiumBlock: big.NewInt(0),
+ ConstantinopleBlock: big.NewInt(0),
+ PetersburgBlock: big.NewInt(0),
+ IstanbulBlock: big.NewInt(0),
+ BerlinBlock: big.NewInt(0),
+ LondonBlock: big.NewInt(0),
+ WorldlandBlock: big.NewInt(0),
+ SeoulBlock: big.NewInt(0),
+ AnnapurnaBlock: big.NewInt(0),
+ MioBlock: big.NewInt(0),
+ HalvingEndTime: big.NewInt(25228800),
+ Kaiju: new(KaijuConfig),
}
-
+
/* SeoulTrustedCheckpoint contains the light client trusted checkpoint for the Gwangju test network.
SeoulTrustedCheckpoint = &TrustedCheckpoint{
SectionIndex: 32,
@@ -346,7 +369,7 @@ var (
CHTRoot: common.HexToHash("0x6504db73139f75ffa9102ae980e41b361cf3d5b66cea06c79cde9f457368820c"),
BloomRoot: common.HexToHash("0x7551ae027bb776252a20ded51ee2ff0cbfbd1d8d57261b9161cc1f2f80237001"),
}
-
+
// SeoulCheckpointOracle contains a set of configs for the Gwangju network oracle.
SeoulCheckpointOracle = &CheckpointOracleConfig{
Address: common.HexToAddress("0x18CA0E045F0D772a851BC7e48357Bcaab0a0795D"),
@@ -360,67 +383,67 @@ var (
Threshold: 2,
}*/
/*
- WorldlandtestChainConfig = &ChainConfig{
- ChainID: big.NewInt(1), //10001
- HomesteadBlock: big.NewInt(1_150_000),
- DAOForkBlock: big.NewInt(1_920_000),
- DAOForkSupport: true,
- EIP150Block: big.NewInt(2_463_000),
- EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
- EIP155Block: big.NewInt(2_675_000),
- EIP158Block: big.NewInt(2_675_000),
- ByzantiumBlock: big.NewInt(4_370_000),
- ConstantinopleBlock: big.NewInt(7_280_000),
- PetersburgBlock: big.NewInt(7_280_000),
- IstanbulBlock: big.NewInt(9_069_000),
- MuirGlacierBlock: big.NewInt(9_200_000),
- BerlinBlock: big.NewInt(12_244_000),
- LondonBlock: big.NewInt(12_965_000),
- ArrowGlacierBlock: big.NewInt(13_773_000),
- GrayGlacierBlock: big.NewInt(15_050_000),
- //EthPoWForkBlock: big.NewInt(15_537_394),
- //EthPoWForkSupport: true,
- //ChainID_ALT: big.NewInt(10001), //10001
- TerminalTotalDifficulty: nil, // 58_750_000_000_000_000_000_000
- Ethash: new(EthashConfig),
- }
+ WorldlandtestChainConfig = &ChainConfig{
+ ChainID: big.NewInt(1), //10001
+ HomesteadBlock: big.NewInt(1_150_000),
+ DAOForkBlock: big.NewInt(1_920_000),
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(2_463_000),
+ EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
+ EIP155Block: big.NewInt(2_675_000),
+ EIP158Block: big.NewInt(2_675_000),
+ ByzantiumBlock: big.NewInt(4_370_000),
+ ConstantinopleBlock: big.NewInt(7_280_000),
+ PetersburgBlock: big.NewInt(7_280_000),
+ IstanbulBlock: big.NewInt(9_069_000),
+ MuirGlacierBlock: big.NewInt(9_200_000),
+ BerlinBlock: big.NewInt(12_244_000),
+ LondonBlock: big.NewInt(12_965_000),
+ ArrowGlacierBlock: big.NewInt(13_773_000),
+ GrayGlacierBlock: big.NewInt(15_050_000),
+ //EthPoWForkBlock: big.NewInt(15_537_394),
+ //EthPoWForkSupport: true,
+ //ChainID_ALT: big.NewInt(10001), //10001
+ TerminalTotalDifficulty: nil, // 58_750_000_000_000_000_000_000
+ Ethash: new(EthashConfig),
+ }
- // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network.
- WorldlandtestTrustedCheckpoint = &TrustedCheckpoint{
- SectionIndex: 451,
- SectionHead: common.HexToHash("0xe47f84b9967eb2ad2afff74d59901b63134660011822fdababaf8fdd18a75aa6"),
- CHTRoot: common.HexToHash("0xc31e0462ca3d39a46111bb6b63ac4e1cac84089472b7474a319d582f72b3f0c0"),
- BloomRoot: common.HexToHash("0x7c9f25ce3577a3ab330d52a7343f801899cf9d4980c69f81de31ccc1a055c809"),
- }
+ // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network.
+ WorldlandtestTrustedCheckpoint = &TrustedCheckpoint{
+ SectionIndex: 451,
+ SectionHead: common.HexToHash("0xe47f84b9967eb2ad2afff74d59901b63134660011822fdababaf8fdd18a75aa6"),
+ CHTRoot: common.HexToHash("0xc31e0462ca3d39a46111bb6b63ac4e1cac84089472b7474a319d582f72b3f0c0"),
+ BloomRoot: common.HexToHash("0x7c9f25ce3577a3ab330d52a7343f801899cf9d4980c69f81de31ccc1a055c809"),
+ }
- // MainnetCheckpointOracle contains a set of configs for the main network oracle.
- WorldlandtestCheckpointOracle = &CheckpointOracleConfig{
- Address: common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"),
- Signers: []common.Address{
- common.HexToAddress("0x1b2C260efc720BE89101890E4Db589b44E950527"), // Peter
- common.HexToAddress("0x78d1aD571A1A09D60D9BBf25894b44e4C8859595"), // Martin
- common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt
- common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary
- common.HexToAddress("0x0DF8fa387C602AE62559cC4aFa4972A7045d6707"), // Guillaume
- },
- Threshold: 2,
- }*/
+ // MainnetCheckpointOracle contains a set of configs for the main network oracle.
+ WorldlandtestCheckpointOracle = &CheckpointOracleConfig{
+ Address: common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"),
+ Signers: []common.Address{
+ common.HexToAddress("0x1b2C260efc720BE89101890E4Db589b44E950527"), // Peter
+ common.HexToAddress("0x78d1aD571A1A09D60D9BBf25894b44e4C8859595"), // Martin
+ common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt
+ common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary
+ common.HexToAddress("0x0DF8fa387C602AE62559cC4aFa4972A7045d6707"), // Guillaume
+ },
+ Threshold: 2,
+ }*/
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Ethash consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
- AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil, nil}
+ AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil, nil, nil}
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Clique consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
- AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
+ AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, nil}
- TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil, nil}
+ TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil, nil, nil}
//NonActivatedConfig = &ChainConfig{big.NewInt(1), nil, nil, false, nil, common.Hash{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil, nil}
TestRules = TestChainConfig.Rules(new(big.Int), false)
)
@@ -432,8 +455,9 @@ var NetworkNames = map[string]string{
RinkebyChainConfig.ChainID.String(): "rinkeby",
GoerliChainConfig.ChainID.String(): "goerli",
SepoliaChainConfig.ChainID.String(): "sepolia",
- SeoulChainConfig.ChainID.String(): "seoul",
- GwangjuChainConfig.ChainID.String(): "gwangju",
+ SeoulChainConfig.ChainID.String(): "seoul",
+ GwangjuChainConfig.ChainID.String(): "gwangju",
+ MioChainConfig.ChainID.String(): "mio",
}
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
@@ -517,10 +541,11 @@ type ChainConfig struct {
ShanghaiBlock *big.Int `json:"shanghaiBlock,omitempty"` // Shanghai switch block (nil = no fork, 0 = already on shanghai)
CancunBlock *big.Int `json:"cancunBlock,omitempty"` // Cancun switch block (nil = no fork, 0 = already on cancun)
- WorldlandBlock *big.Int `json:"worldlandBlock,omitempty"` // worldrand switch block (nil = no fork, 0 = already on worldland)
- HalvingEndTime *big.Int `json:"HalvingEndTime,omitempty"`
- SeoulBlock *big.Int `json:"seoulBlock,omitempty"`
- AnnapurnaBlock *big.Int `json:"AnnapurnaBlock,omitempty"`
+ WorldlandBlock *big.Int `json:"worldlandBlock,omitempty"` // worldrand switch block (nil = no fork, 0 = already on worldland)
+ HalvingEndTime *big.Int `json:"HalvingEndTime,omitempty"`
+ SeoulBlock *big.Int `json:"seoulBlock,omitempty"`
+ AnnapurnaBlock *big.Int `json:"AnnapurnaBlock,omitempty"`
+ MioBlock *big.Int `json:"MioBlock,omitempty"`
// TerminalTotalDifficulty is the amount of total difficulty reached by
// the network that triggers the consensus upgrade.
@@ -535,6 +560,8 @@ type ChainConfig struct {
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
Eccpow *EccpowConfig `json:"eccpow,omitempty"`
+ Kaiju *KaijuConfig `json:"kaiju,omitempty"`
+
}
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
@@ -543,6 +570,10 @@ type EthashConfig struct{}
// EccpowConfig is the consensus engine configs for proof-of-work based sealing.
type EccpowConfig struct{}
+// AbcdkConfig is the consensus engine configs for proof-of-work based sealing.
+type KaijuConfig struct{}
+
+
// String implements the stringer interface, returning the consensus engine details.
func (c *EthashConfig) String() string {
return "ethash"
@@ -553,6 +584,10 @@ func (c *EccpowConfig) String() string {
return "eccpow"
}
+func (c *KaijuConfig) String() string {
+ return "Kaiju"
+}
+
// CliqueConfig is the consensus engine configs for proof-of-authority based sealing.
type CliqueConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
@@ -599,6 +634,14 @@ func (c *ChainConfig) String() string {
} else {
banner += "Consensus: Beacon (proof-of-stake), merged from Eccpow (proof-of-work)\n"
}
+ case c.Kaiju != nil:
+ if c.TerminalTotalDifficulty == nil {
+ banner += "Consensus: Kaiju (proof-of-work with VRF sortition)\n"
+ } else if !c.TerminalTotalDifficultyPassed {
+ banner += "Consensus: Kaiju (proof-of-work with VRF sortition)\n"
+ } else {
+ banner += "Consensus: Kaiju (proof-of-work with VRF sortition)\n"
+ }
default:
banner += "Consensus: unknown\n"
}
@@ -637,17 +680,17 @@ func (c *ChainConfig) String() string {
banner += fmt.Sprintf(" - Cancun: %-8v\n", c.CancunBlock)
}*/
/*
- if c.WorldlandBlock != nil {
- banner += fmt.Sprintf(" - Worldland: %-8v\n", c.WorldlandBlock)
- }
- if c.SeoulBlock != nil {
- banner += fmt.Sprintf(" - Seoul: %-8v\n", c.SeoulBlock)
- }*/
+ if c.WorldlandBlock != nil {
+ banner += fmt.Sprintf(" - Worldland: %-8v\n", c.WorldlandBlock)
+ }
+ if c.SeoulBlock != nil {
+ banner += fmt.Sprintf(" - Seoul: %-8v\n", c.SeoulBlock)
+ }*/
if c.AnnapurnaBlock != nil {
banner += fmt.Sprintf(" - Annapurna: %-8v\n", c.AnnapurnaBlock)
}
banner += "\n"
-
+
// Add a special section for the merge as it's non-obvious
/*if c.TerminalTotalDifficulty == nil {
banner += "The Merge is not yet available for this network!\n"
@@ -780,6 +823,9 @@ func (c *ChainConfig) IsAnnapurna(num *big.Int) bool {
return isForked(c.AnnapurnaBlock, num)
}
+func (c *ChainConfig) IsMio(num *big.Int) bool {
+ return isForked(c.MioBlock, num)
+}
// CheckCompatible checks whether scheduled fork transitions have been imported
// with a mismatching chain configuration.
@@ -1016,7 +1062,7 @@ type Rules struct {
IsMerge, IsShanghai, isCancun bool
IsWorldland bool
IsSeoul bool
- IsAnnapurna bool
+ IsAnnapurna bool
}
// Rules ensures c's ChainID is not nil.
@@ -1042,6 +1088,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool) Rules {
isCancun: c.IsCancun(num),
IsWorldland: c.IsWorldland(num),
IsSeoul: c.IsSeoul(num),
- IsAnnapurna: c.IsAnnapurna(num),
+ IsAnnapurna: c.IsAnnapurna(num),
}
}