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), } }