Merge branch 'master' into network_specific_methods_support
# Conflicts: # src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt
This commit is contained in:
32
.github/workflows/test.yaml
vendored
32
.github/workflows/test.yaml
vendored
@@ -40,35 +40,3 @@ jobs:
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./build/reports/jacoco/test/jacocoTestReport.xml
|
||||
|
||||
integration-test:
|
||||
runs-on: ubuntu-latest
|
||||
# Docker Hub image that `container-job` executes in.
|
||||
# Use -buster which comes with Git 2.20, because action/checkout needs Git 2.18+ to make correct clone (needed by Gradle version plugin)
|
||||
container: node:12-buster
|
||||
services:
|
||||
redis:
|
||||
image: redis
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 13
|
||||
|
||||
- name: Check
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
arguments: check
|
||||
env:
|
||||
CI: true
|
||||
DSHACKLE_TEST_ENABLED: redis
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "emerald-java-client"]
|
||||
path = emerald-java-client
|
||||
url = https://github.com/p2p-org/emerald-java-client.git
|
||||
[submodule "dshackle-cli/grpc"]
|
||||
path = dshackle-cli/grpc
|
||||
url = https://github.com/p2p-org/emerald-grpc.git
|
||||
[submodule "emerald-grpc"]
|
||||
path = emerald-grpc
|
||||
url = git@github.com:p2p-org/emerald-grpc.git
|
||||
|
||||
36
build.gradle
36
build.gradle
@@ -5,6 +5,15 @@ import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.1'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'groovy'
|
||||
@@ -49,6 +58,7 @@ configurations {
|
||||
compile.exclude group: "org.slf4j", module: "log4j-over-slf4j"
|
||||
// should be used only for generation of the stubs, the lib contains grpc classes
|
||||
compile.exclude group: "com.salesforce.servicelibs", module: "reactor-grpc"
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -70,10 +80,6 @@ dependencies {
|
||||
|
||||
implementation libs.bundles.etherjar
|
||||
|
||||
implementation(libs.emerald.api) {
|
||||
exclude group: 'com.salesforce.servicelibs', module: 'reactor-grpc'
|
||||
}
|
||||
|
||||
implementation libs.bitcoinj
|
||||
|
||||
implementation libs.snake.yaml
|
||||
@@ -96,6 +102,13 @@ dependencies {
|
||||
testImplementation libs.java.websocket
|
||||
testImplementation libs.equals.verifier
|
||||
testImplementation libs.groovy
|
||||
testImplementation libs.bundles.testcontainers
|
||||
testImplementation libs.bundles.junit
|
||||
|
||||
testImplementation(libs.spring.boot.starter.test) {
|
||||
exclude module: 'spring-boot-starter-logging'
|
||||
}
|
||||
testImplementation libs.grpc.testing
|
||||
|
||||
detektPlugins libs.detekt.formatting
|
||||
}
|
||||
@@ -188,14 +201,26 @@ protobuf {
|
||||
artifact = System.getenv("PROTOC_PATH") == null ? "com.google.protobuf:protoc:${libs.versions.protoc.get()}" : null
|
||||
}
|
||||
plugins {
|
||||
grpc {
|
||||
artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
|
||||
}
|
||||
reactor { artifact = "com.salesforce.servicelibs:reactor-grpc:${reactiveGrpcVersion}" }
|
||||
}
|
||||
generateProtoTasks {
|
||||
all()*.plugins {
|
||||
grpc {}
|
||||
reactor {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources.srcDirs += project.buildDir.absolutePath + "/generated/version"
|
||||
|
||||
proto {
|
||||
srcDir 'emerald-grpc/proto'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,3 +314,6 @@ detekt {
|
||||
tasks.withType(Detekt).configureEach {
|
||||
jvmTarget = "13"
|
||||
}
|
||||
|
||||
// formats code for each build
|
||||
tasks.findByName("ktlintCheck").dependsOn("ktlintFormat")
|
||||
|
||||
Submodule dshackle-cli/grpc deleted from 4060e53997
@@ -3,7 +3,7 @@ const path = require('path')
|
||||
const protoLoader = require("@grpc/proto-loader");
|
||||
const fs = require('fs');
|
||||
|
||||
const PROTO_PATH = path.join(__dirname, "../grpc/proto/blockchain.proto");
|
||||
const PROTO_PATH = path.join(__dirname, "../../emerald-grpc/proto/blockchain.proto");
|
||||
|
||||
const options = {
|
||||
keepCase: true,
|
||||
|
||||
1
emerald-grpc
Submodule
1
emerald-grpc
Submodule
Submodule emerald-grpc added at 441f828eb6
Submodule emerald-java-client deleted from 35196f35f3
@@ -1,3 +1,6 @@
|
||||
kotlin.code.style=official
|
||||
|
||||
grpcVersion=1.49.2
|
||||
reactiveGrpcVersion=1.2.0
|
||||
|
||||
|
||||
|
||||
@@ -31,8 +31,6 @@ cglib-nodep = "cglib:cglib-nodep:3.3.0"
|
||||
|
||||
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
||||
|
||||
emerald-api = "io.emeraldpay:emerald-api:0.12-alpha.3"
|
||||
|
||||
equals-verifier = "nl.jqno.equalsverifier:equalsverifier:3.10.1"
|
||||
|
||||
etherjar-domain = { module = "io.emeraldpay.etherjar:etherjar-domain", version.ref = "etherjar" }
|
||||
@@ -113,6 +111,14 @@ spring-security-core = { module = "org.springframework.security:spring-security-
|
||||
spring-security-web = { module = "org.springframework.security:spring-security-web", version.ref = "spring-security" }
|
||||
spring-security-config = { module = "org.springframework.security:spring-security-config", version.ref = "spring-security" }
|
||||
|
||||
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
|
||||
|
||||
testcontainers = "org.testcontainers:testcontainers:1.17.5"
|
||||
testcontainers-ganache = "io.github.ganchix:testcontainers-java-module-ganache:0.0.4"
|
||||
|
||||
junit-jupiter = "org.junit.jupiter:junit-jupiter:5.9.1"
|
||||
assertj = "org.assertj:assertj-core:3.23.1"
|
||||
|
||||
[bundles]
|
||||
apache-commons = ["commons-io", "apache-commons-lang3", "apache-commons-collections4"]
|
||||
etherjar = ["etherjar-domain", "etherjar-hex", "etherjar-rpc-api", "etherjar-rpc-http", "etherjar-rpc-ws", "etherjar-tx", "etherjar-contract", "etherjar-erc20"]
|
||||
@@ -124,12 +130,15 @@ netty = ["netty-common", "netty-transport", "netty-handler-core", "netty-handler
|
||||
reactor = ["reactor-core", "reactor-netty", "reactor-extra", "reactor-kotlin"]
|
||||
slf4j = ["slf4j-api", "slf4j-jul", "slf4j-jcl", "log4j-slf4j"]
|
||||
spring-framework = ["spring-boot-starter", "spring-security-core", "spring-security-web", "spring-security-config"]
|
||||
testcontainers = ["testcontainers", "testcontainers-ganache"]
|
||||
junit = ["junit-jupiter", "assertj"]
|
||||
|
||||
|
||||
[plugins]
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
jib = { id = "com.google.cloud.tools.jib", version = "2.5.0" }
|
||||
spring = { id = "org.springframework.boot", version = "2.3.5.RELEASE" }
|
||||
git = { id = "com.palantir.git-version", version = "0.12.3" }
|
||||
protobuf = { id = "com.google.protobuf", version = "0.8.17" }
|
||||
protobuf = { id = "com.google.protobuf", version = "0.9.1" }
|
||||
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "10.2.0" }
|
||||
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
||||
@@ -1,45 +0,0 @@
|
||||
{ system ? builtins.currentSystem
|
||||
, nixpkgs ? import ./nixpkgs.nix { inherit system; }
|
||||
}:
|
||||
let
|
||||
mkEnv = nixpkgs.callPackage ./mkEnv.nix { };
|
||||
in
|
||||
rec {
|
||||
inherit
|
||||
nixpkgs
|
||||
;
|
||||
|
||||
protoc-gen-grpc-java = nixpkgs.callPackage ./pkgs/protoc-gen-grpc-java { };
|
||||
|
||||
env = mkEnv {
|
||||
env = {
|
||||
# Configure nix to use nixpgks
|
||||
NIX_PATH = "nixpkgs=${toString nixpkgs.path}";
|
||||
# Set the env for gradle
|
||||
JAVA_HOME = "@env-root@/lib/openjdk";
|
||||
};
|
||||
|
||||
paths = [
|
||||
# Development tools
|
||||
nixpkgs.gitAndTools.git-absorb
|
||||
nixpkgs.jq
|
||||
nixpkgs.niv
|
||||
nixpkgs.websocat
|
||||
nixpkgs.yq
|
||||
|
||||
# Protobuf stuff
|
||||
nixpkgs.protobuf3_9
|
||||
protoc-gen-grpc-java
|
||||
|
||||
# Code formatting
|
||||
nixpkgs.treefmt
|
||||
nixpkgs.nixpkgs-fmt
|
||||
nixpkgs.shfmt
|
||||
|
||||
nixpkgs.jdk
|
||||
nixpkgs.coreutils
|
||||
nixpkgs.gnugrep
|
||||
nixpkgs.which
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
# Source https://github.com/Mic92/nix-build-uncached/blob/master/scripts/force_cached.nix
|
||||
coreutils: attrs:
|
||||
with builtins;
|
||||
let
|
||||
# Copied from <nixpkgs/lib>
|
||||
isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
|
||||
|
||||
# Return true if `nix-build` would traverse that attribute set to look for
|
||||
# more derivations to build.
|
||||
hasRecurseIntoAttrs = x: isAttrs x && (x.recurseForDerivations or false);
|
||||
|
||||
# Wraps derivations that disallow substitutes so that they can be cached.
|
||||
toCachedDrv = drv:
|
||||
if !(drv.allowSubstitutes or true) then
|
||||
derivation
|
||||
{
|
||||
name = "${drv.name}-to-cached";
|
||||
system = drv.system;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "${coreutils}/bin/ln -s ${drv} $out; exit 0" ];
|
||||
}
|
||||
else
|
||||
drv;
|
||||
|
||||
op = _: val:
|
||||
if isDerivation val then
|
||||
toCachedDrv val
|
||||
else if hasRecurseIntoAttrs val then
|
||||
forceCached val
|
||||
else
|
||||
val
|
||||
;
|
||||
|
||||
# Traverses a tree of derivation and wrap all of those that disallow
|
||||
# substitutes.
|
||||
forceCached = attrs: mapAttrs op attrs;
|
||||
in
|
||||
forceCached attrs
|
||||
@@ -1,29 +0,0 @@
|
||||
{ lib, writeText, buildEnv }:
|
||||
|
||||
{ name ? "dev-env"
|
||||
, # Environment variables to set
|
||||
env ? { }
|
||||
, # Packages to add to the path
|
||||
paths ? [ ]
|
||||
}:
|
||||
let
|
||||
envToBash = name: value:
|
||||
"export ${name}=${lib.escapeShellArg (toString value)}"
|
||||
;
|
||||
|
||||
exports = lib.concatStringsSep "\n"
|
||||
(map (name: envToBash name env.${name}) (lib.attrNames env));
|
||||
|
||||
env-root = writeText "env-root" ''
|
||||
export PATH=@env-root@/bin:$PATH
|
||||
|
||||
${exports}
|
||||
'';
|
||||
in
|
||||
buildEnv {
|
||||
inherit name;
|
||||
paths = paths;
|
||||
postBuild = ''
|
||||
sed "s|@env-root@|$out|g" ${env-root} > $out/.profile
|
||||
'';
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{ system ? builtins.currentSystem }:
|
||||
let
|
||||
sources = import ./sources.nix;
|
||||
in
|
||||
import sources.nixpkgs {
|
||||
inherit system;
|
||||
config = { };
|
||||
overlays = [ ];
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{ stdenv, runCommand, fetchurl, autoPatchelfHook, lib }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "protoc-gen-grpc-java";
|
||||
version = "1.38.0";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/${version}/protoc-gen-grpc-java-${version}-linux-x86_64.exe";
|
||||
sha256 = "sha256:1gy5lkxj6d4vrgalwnjp15biybcnrmp695si9878y7high39ymr3";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ autoPatchelfHook ];
|
||||
|
||||
unpackPhase = ''
|
||||
cp $src ./bin
|
||||
chmod +x ./bin
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
mv ./bin $out/bin/$pname
|
||||
'';
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
# Use this file with nix-build-uncached on CI
|
||||
{ system ? builtins.currentSystem }:
|
||||
let
|
||||
nixpkgs = import ./nixpkgs.nix { inherit system; };
|
||||
|
||||
# This is used to wrap all of our outputs, so they all end-up in the cache.
|
||||
#
|
||||
# There are two attributes ` allowSubstitutes = false;` and
|
||||
# `preferLocalBuild = true;` that influence how derivations gets pulled and
|
||||
# pushed.
|
||||
forceCached = import ./lib/force_cached.nix nixpkgs.coreutils;
|
||||
|
||||
# All the packages that we care about
|
||||
ourPackages = import ./. { inherit nixpkgs system; };
|
||||
in
|
||||
forceCached ourPackages
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"nixpkgs": {
|
||||
"branch": "nixos-unstable",
|
||||
"description": "Nix Packages collection",
|
||||
"homepage": "",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e4ef597edfd8a0ba5f12362932fc9b1dd01a0aef",
|
||||
"sha256": "1w6y7ma2crcsfph60z8j1k3af0v2m110cbjrb62z287mn4skhqjs",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/e4ef597edfd8a0ba5f12362932fc9b1dd01a0aef.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
}
|
||||
}
|
||||
160
nix/sources.nix
160
nix/sources.nix
@@ -1,160 +0,0 @@
|
||||
# This file has been generated by Niv.
|
||||
let
|
||||
#
|
||||
# The fetchers. fetch_<type> fetches specs of type <type>.
|
||||
#
|
||||
|
||||
fetch_file = pkgs: name: spec:
|
||||
let
|
||||
name' = sanitizeName name + "-src";
|
||||
in
|
||||
if spec.builtin or true then
|
||||
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
|
||||
else
|
||||
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
|
||||
|
||||
fetch_tarball = pkgs: name: spec:
|
||||
let
|
||||
name' = sanitizeName name + "-src";
|
||||
in
|
||||
if spec.builtin or true then
|
||||
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
|
||||
else
|
||||
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
|
||||
|
||||
fetch_git = name: spec:
|
||||
let
|
||||
ref =
|
||||
if spec ? ref then spec.ref else
|
||||
if spec ? branch then "refs/heads/${spec.branch}" else
|
||||
if spec ? tag then "refs/tags/${spec.tag}" else
|
||||
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
|
||||
in
|
||||
builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
|
||||
|
||||
fetch_local = spec: spec.path;
|
||||
|
||||
fetch_builtin-tarball = name: throw
|
||||
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
|
||||
$ niv modify ${name} -a type=tarball -a builtin=true'';
|
||||
|
||||
fetch_builtin-url = name: throw
|
||||
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
|
||||
$ niv modify ${name} -a type=file -a builtin=true'';
|
||||
|
||||
#
|
||||
# Various helpers
|
||||
#
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
|
||||
sanitizeName = name:
|
||||
(
|
||||
concatMapStrings (s: if builtins.isList s then "-" else s)
|
||||
(
|
||||
builtins.split "[^[:alnum:]+._?=-]+"
|
||||
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
|
||||
)
|
||||
);
|
||||
|
||||
# The actual fetching function.
|
||||
fetch = pkgs: name: spec:
|
||||
|
||||
if ! builtins.hasAttr "type" spec then
|
||||
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
|
||||
else if spec.type == "file" then fetch_file pkgs name spec
|
||||
else if spec.type == "tarball" then fetch_tarball pkgs name spec
|
||||
else if spec.type == "git" then fetch_git name spec
|
||||
else if spec.type == "local" then fetch_local spec
|
||||
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
|
||||
else if spec.type == "builtin-url" then fetch_builtin-url name
|
||||
else
|
||||
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
|
||||
|
||||
# If the environment variable NIV_OVERRIDE_${name} is set, then use
|
||||
# the path directly as opposed to the fetched source.
|
||||
replace = name: drv:
|
||||
let
|
||||
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
|
||||
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
|
||||
in
|
||||
if ersatz == "" then drv else
|
||||
# this turns the string into an actual Nix path (for both absolute and
|
||||
# relative paths)
|
||||
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
|
||||
|
||||
# Ports of functions for older nix versions
|
||||
|
||||
# a Nix version of mapAttrs if the built-in doesn't exist
|
||||
mapAttrs = builtins.mapAttrs or (
|
||||
f: set: with builtins;
|
||||
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
|
||||
);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
||||
range = first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
||||
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
||||
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
||||
concatMapStrings = f: list: concatStrings (map f list);
|
||||
concatStrings = builtins.concatStringsSep "";
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
|
||||
optionalAttrs = cond: as: if cond then as else { };
|
||||
|
||||
# fetchTarball version that is compatible between all the versions of Nix
|
||||
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
|
||||
let
|
||||
inherit (builtins) lessThan nixVersion fetchTarball;
|
||||
in
|
||||
if lessThan nixVersion "1.12" then
|
||||
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
||||
else
|
||||
fetchTarball attrs;
|
||||
|
||||
# fetchurl version that is compatible between all the versions of Nix
|
||||
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
|
||||
let
|
||||
inherit (builtins) lessThan nixVersion fetchurl;
|
||||
in
|
||||
if lessThan nixVersion "1.12" then
|
||||
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
||||
else
|
||||
fetchurl attrs;
|
||||
|
||||
# Create the final "sources" from the config
|
||||
mkSources = config:
|
||||
mapAttrs
|
||||
(
|
||||
name: spec:
|
||||
if builtins.hasAttr "outPath" spec
|
||||
then
|
||||
abort
|
||||
"The values in sources.json should not have an 'outPath' attribute"
|
||||
else
|
||||
spec // { outPath = replace name (fetch config.pkgs name spec); }
|
||||
)
|
||||
config.sources;
|
||||
|
||||
# The "config" used by the fetchers
|
||||
mkConfig =
|
||||
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
|
||||
, sources ? if isNull sourcesFile then { } else builtins.fromJSON (builtins.readFile sourcesFile)
|
||||
, system ? builtins.currentSystem
|
||||
, pkgs ? abort ''
|
||||
Some source is being used outside of nixpkgs. For example using import.
|
||||
|
||||
Edit the sources.json and add `"builtin": true` to that source.
|
||||
''
|
||||
}: rec {
|
||||
# The sources, i.e. the attribute set of spec name to spec
|
||||
inherit sources;
|
||||
|
||||
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
|
||||
inherit pkgs;
|
||||
};
|
||||
|
||||
in
|
||||
mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); }
|
||||
@@ -1,7 +0,0 @@
|
||||
= Emerald Dshackle Protobuf definitions
|
||||
|
||||
Protobuf definition for the external interface (i.e. gRPC) of the Emerald Dshackle.
|
||||
This gRPC definitions are part of the general Emerald API, please see the project with whole API at https://github.com/emeraldpay/emerald-grpc
|
||||
|
||||
Dshakle also has some internal Protobuf schemas, for example to serialize cached values.
|
||||
You can find them in link:../src/main/proto/[].
|
||||
@@ -1,284 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package emerald;
|
||||
option java_package = "io.emeraldpay.api.proto";
|
||||
import "common.proto";
|
||||
|
||||
service Blockchain {
|
||||
rpc SubscribeHead (Chain) returns (stream ChainHead) {}
|
||||
rpc SubscribeBalance (BalanceRequest) returns (stream AddressBalance) {}
|
||||
rpc SubscribeTxStatus (TxStatusRequest) returns (stream TxStatus) {}
|
||||
|
||||
rpc GetBalance (BalanceRequest) returns (stream AddressBalance) {}
|
||||
|
||||
/**
|
||||
* Fee Estimation service. The server tries to estimate a fair fee based on the last N blocks.
|
||||
*/
|
||||
rpc EstimateFee (EstimateFeeRequest) returns (EstimateFeeResponse) {}
|
||||
|
||||
rpc NativeCall (NativeCallRequest) returns (stream NativeCallReplyItem) {}
|
||||
rpc NativeSubscribe (NativeSubscribeRequest) returns (stream NativeSubscribeReplyItem) {}
|
||||
|
||||
rpc Describe (DescribeRequest) returns (DescribeResponse) {}
|
||||
rpc SubscribeStatus (StatusRequest) returns (stream ChainStatus) {}
|
||||
}
|
||||
|
||||
message NativeCallRequest {
|
||||
ChainRef chain = 1;
|
||||
repeated NativeCallItem items = 2;
|
||||
Selector selector = 3;
|
||||
int32 quorum = 4;
|
||||
AvailabilityEnum min_availability = 5;
|
||||
}
|
||||
|
||||
message NativeCallItem {
|
||||
uint32 id = 1;
|
||||
string method = 3;
|
||||
bytes payload = 4;
|
||||
uint64 nonce = 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature for a response
|
||||
*/
|
||||
message NativeCallReplySignature {
|
||||
/**
|
||||
* Original nonce value used for the call
|
||||
*/
|
||||
uint64 nonce = 1;
|
||||
/**
|
||||
* Signature value
|
||||
*/
|
||||
bytes signature = 2;
|
||||
/**
|
||||
* Key Id used for the signing
|
||||
*/
|
||||
uint64 key_id = 3;
|
||||
/**
|
||||
* Id of the upstream produced the response
|
||||
*/
|
||||
string upstream_id = 4;
|
||||
}
|
||||
|
||||
message NativeCallReplyItem {
|
||||
uint32 id = 1;
|
||||
bool succeed = 2;
|
||||
bytes payload = 3;
|
||||
string errorMessage = 4;
|
||||
/**
|
||||
* Optional signature for the response.
|
||||
* Available only when it's configured at the edge dshackle and nonce is provided wit the request.
|
||||
*/
|
||||
NativeCallReplySignature signature = 5;
|
||||
}
|
||||
|
||||
message NativeSubscribeRequest {
|
||||
ChainRef chain = 1;
|
||||
string method = 2;
|
||||
bytes payload = 3;
|
||||
}
|
||||
|
||||
message NativeSubscribeReplyItem {
|
||||
bytes payload = 1;
|
||||
}
|
||||
|
||||
message ChainHead {
|
||||
ChainRef chain = 1;
|
||||
uint64 height = 2;
|
||||
string block_id = 3;
|
||||
uint64 timestamp = 4;
|
||||
bytes weight = 5;
|
||||
uint64 reorg = 6;
|
||||
}
|
||||
|
||||
message TxStatusRequest {
|
||||
ChainRef chain = 1;
|
||||
string tx_id = 2;
|
||||
uint32 confirmation_limit = 3;
|
||||
}
|
||||
|
||||
message TxStatus {
|
||||
string tx_id = 1;
|
||||
bool broadcasted = 2;
|
||||
bool mined = 3;
|
||||
BlockInfo block = 4;
|
||||
uint32 confirmations = 5;
|
||||
}
|
||||
|
||||
message BalanceRequest {
|
||||
Asset asset = 1;
|
||||
AnyAddress address = 2;
|
||||
bool include_utxo = 3;
|
||||
}
|
||||
|
||||
message AddressBalance {
|
||||
Asset asset = 1;
|
||||
SingleAddress address = 2;
|
||||
string balance = 3;
|
||||
bool confirmed = 4;
|
||||
repeated Utxo utxo = 5;
|
||||
}
|
||||
|
||||
message Utxo {
|
||||
string tx_id = 1;
|
||||
uint64 index = 2;
|
||||
string balance = 3;
|
||||
bool spent = 4;
|
||||
}
|
||||
|
||||
message DescribeRequest {
|
||||
}
|
||||
|
||||
message DescribeResponse {
|
||||
repeated DescribeChain chains = 1;
|
||||
}
|
||||
|
||||
message DescribeChain {
|
||||
ChainRef chain = 1;
|
||||
ChainStatus status = 2;
|
||||
repeated NodeDetails nodes = 3;
|
||||
repeated string supportedMethods = 4;
|
||||
repeated string excludedMethods = 5;
|
||||
repeated Capabilities capabilities = 6;
|
||||
}
|
||||
|
||||
message StatusRequest {
|
||||
repeated ChainRef chains = 1;
|
||||
}
|
||||
|
||||
message ChainStatus {
|
||||
ChainRef chain = 1;
|
||||
AvailabilityEnum availability = 2;
|
||||
uint32 quorum = 3;
|
||||
}
|
||||
|
||||
enum AvailabilityEnum {
|
||||
AVAIL_UNKNOWN = 0;
|
||||
AVAIL_OK = 1;
|
||||
AVAIL_LAGGING = 2;
|
||||
AVAIL_IMMATURE = 3;
|
||||
AVAIL_SYNCING = 4;
|
||||
AVAIL_UNAVAILABLE = 5;
|
||||
}
|
||||
|
||||
message NodeDetails {
|
||||
uint32 quorum = 1;
|
||||
repeated Label labels = 2;
|
||||
}
|
||||
|
||||
enum Capabilities {
|
||||
CAP_NONE = 0;
|
||||
CAP_CALLS = 1;
|
||||
CAP_BALANCE = 2;
|
||||
}
|
||||
|
||||
message Label {
|
||||
string name = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
message Selector {
|
||||
oneof selector_type {
|
||||
LabelSelector labelSelector = 1;
|
||||
OrSelector orSelector = 2;
|
||||
AndSelector andSelector = 3;
|
||||
NotSelector notSelector = 4;
|
||||
ExistsSelector existsSelector = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message LabelSelector {
|
||||
string name = 1;
|
||||
repeated string value = 2;
|
||||
}
|
||||
|
||||
message OrSelector {
|
||||
repeated Selector selectors = 1;
|
||||
}
|
||||
|
||||
message AndSelector {
|
||||
repeated Selector selectors = 1;
|
||||
}
|
||||
|
||||
message NotSelector {
|
||||
Selector selector = 1;
|
||||
}
|
||||
|
||||
message ExistsSelector {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request for Fee Estimation Service
|
||||
*/
|
||||
message EstimateFeeRequest {
|
||||
// Target chain
|
||||
ChainRef chain = 1;
|
||||
// The way how the fee should be estimated
|
||||
FeeEstimationMode mode = 2;
|
||||
// How many blocks the server is supposed to use to estimate current fee. Note that the server may use value, depending on configuration
|
||||
uint32 blocks = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Responset for Fee Estimation Service
|
||||
*/
|
||||
message EstimateFeeResponse {
|
||||
// May return different struct, depending on the blockchain
|
||||
oneof fee_type {
|
||||
// Standard Ethereum Fee, supported by majority of forks and by Ethereum Mainnet before EIP-1559
|
||||
EthereumStdFees ethereumStd = 1;
|
||||
// Ethereum Fee for EIP-1559 compatible forks
|
||||
EthereumExtFees ethereumExtended = 2;
|
||||
// Standard Bitcoin Fee
|
||||
BitcoinStdFees bitcoinStd = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The mode of how the fee must be estimated
|
||||
*/
|
||||
enum FeeEstimationMode {
|
||||
INVALID = 0;
|
||||
// Average over last transaction in each block
|
||||
AVG_LAST = 1;
|
||||
// Average over transaction 5th from the end in each block
|
||||
AVG_T5 = 2;
|
||||
// Average over transaction 20th from the end in each block
|
||||
AVG_T20 = 3;
|
||||
// Average over transaction 50th from the end in each block
|
||||
AVG_T50 = 4;
|
||||
// Minimal fee that would be accepted by every last block
|
||||
MIN_ALWAYS = 5;
|
||||
// Average over transaction in the middle of each block
|
||||
AVG_MIDDLE = 6;
|
||||
// Average over transaction in head of each block. Note that for Bitcoin it doesn't count COINBASE tx as top tx.
|
||||
AVG_TOP = 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Ethereum Fee, supported by majority of forks and by Ethereum Mainnet before EIP-1559
|
||||
*/
|
||||
message EthereumStdFees {
|
||||
// Big Number encoded as string. Fee value in Wei
|
||||
string fee = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ethereum Fee for EIP-1559 compatible forks
|
||||
*/
|
||||
message EthereumExtFees {
|
||||
// Big Number encoded as string. Estimated fee that expected to be actually paid. I.e. it's the Base Fee + Priority Fee
|
||||
string expect = 1;
|
||||
// Big Number encoded as string. Priority Fee in Wei
|
||||
string priority = 2;
|
||||
// Big Number encoded as string. Max Fee value in Wei. Note that it only indicates the current preference, and the actual Max may be significantly lower, depending on the usage scenario.
|
||||
string max = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Bitcoin Fee
|
||||
*/
|
||||
message BitcoinStdFees {
|
||||
// Fee in Satoshi per Kilobyte. Note that the actual fee calculation MUST divide it by 1024 at the last step to get a fair fee.
|
||||
uint64 satPerKb = 1;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package emerald;
|
||||
option java_package = "io.emeraldpay.api.proto";
|
||||
|
||||
message Chain {
|
||||
ChainRef type = 1;
|
||||
}
|
||||
|
||||
enum ChainRef {
|
||||
CHAIN_UNSPECIFIED = 0;
|
||||
|
||||
CHAIN_BITCOIN = 1;
|
||||
// CHAIN_GRIN = 2;
|
||||
|
||||
CHAIN_ETHEREUM = 100;
|
||||
CHAIN_ETHEREUM_CLASSIC = 101;
|
||||
CHAIN_FANTOM = 102; // Fantom, https://fantom.foundation/
|
||||
|
||||
// Sidechains and state channels start with 1_000
|
||||
// CHAIN_LIGHTNING = 1001;
|
||||
CHAIN_MATIC = 1002; // Matic PoS Ethereum sidechain based on Polygon
|
||||
CHAIN_RSK = 1003; // RSK sidechain, https://www.rsk.co/
|
||||
|
||||
// Testnets start with 10_000
|
||||
CHAIN_MORDEN = 10001;
|
||||
CHAIN_KOVAN = 10002;
|
||||
CHAIN_TESTNET_BITCOIN = 10003;
|
||||
// CHAIN_FLOONET = 10004;
|
||||
CHAIN_GOERLI = 10005;
|
||||
CHAIN_ROPSTEN = 10006;
|
||||
CHAIN_RINKEBY = 10007;
|
||||
|
||||
// Non-standard starts from 20_000
|
||||
}
|
||||
|
||||
message SingleAddress {
|
||||
string address = 1;
|
||||
}
|
||||
|
||||
message XpubAddress {
|
||||
bytes xpub = 1;
|
||||
string path = 2;
|
||||
uint64 start = 3;
|
||||
uint64 limit = 4;
|
||||
}
|
||||
|
||||
message MultiAddress {
|
||||
repeated SingleAddress addresses = 1;
|
||||
}
|
||||
|
||||
message ReferenceAddress {
|
||||
uint64 refid = 1;
|
||||
}
|
||||
|
||||
message AnyAddress {
|
||||
oneof addr_type {
|
||||
SingleAddress address_single = 1;
|
||||
MultiAddress address_multi = 2;
|
||||
XpubAddress address_xpub = 3;
|
||||
ReferenceAddress address_ref = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message Asset {
|
||||
ChainRef chain = 1;
|
||||
string code = 2;
|
||||
}
|
||||
|
||||
message BlockInfo {
|
||||
uint64 height = 1;
|
||||
string block_id = 2;
|
||||
uint64 timestamp = 3;
|
||||
bytes weight = 4;
|
||||
}
|
||||
@@ -1,8 +1,2 @@
|
||||
enableFeaturePreview("VERSION_CATALOGS")
|
||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
|
||||
includeBuild('./emerald-java-client') {
|
||||
dependencySubstitution {
|
||||
substitute module('io.emeraldpay:emerald-api:0.12-alpha.3') using project(':')
|
||||
}
|
||||
}
|
||||
36
src/main/kotlin/io/emeraldpay/dshackle/BlockchainType.kt
Normal file
36
src/main/kotlin/io/emeraldpay/dshackle/BlockchainType.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package io.emeraldpay.dshackle
|
||||
|
||||
enum class BlockchainType {
|
||||
BITCOIN, EVM_POW, EVM_POS;
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun from(chain: Chain): BlockchainType {
|
||||
if (chain == Chain.TESTNET_ROPSTEN ||
|
||||
chain == Chain.POLYGON ||
|
||||
chain == Chain.OPTIMISM ||
|
||||
chain == Chain.BSC ||
|
||||
chain == Chain.TESTNET_GOERLI ||
|
||||
chain == Chain.ETHEREUM
|
||||
) {
|
||||
return EVM_POS
|
||||
}
|
||||
if (chain == Chain.ETHEREUM_CLASSIC ||
|
||||
chain == Chain.ARBITRUM ||
|
||||
chain == Chain.FANTOM ||
|
||||
chain == Chain.RSK ||
|
||||
chain == Chain.TESTNET_KOVAN ||
|
||||
chain == Chain.TESTNET_MORDEN ||
|
||||
chain == Chain.TESTNET_RINKEBY
|
||||
) {
|
||||
return EVM_POW
|
||||
}
|
||||
if (chain == Chain.BITCOIN ||
|
||||
chain == Chain.TESTNET_BITCOIN
|
||||
) {
|
||||
return BITCOIN
|
||||
}
|
||||
throw IllegalArgumentException("Unknown type of blockchain: $chain")
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/main/kotlin/io/emeraldpay/dshackle/Chain.kt
Normal file
64
src/main/kotlin/io/emeraldpay/dshackle/Chain.kt
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2019 ETCDEV GmbH, All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle
|
||||
|
||||
enum class Chain(val id: Int, val chainCode: String, val chainName: String) {
|
||||
UNSPECIFIED(0, "UNSPECIFIED", "Unknown"),
|
||||
BITCOIN(1, "BTC", "Bitcoin"), // GRIN(2, "GRIN", "Grin"),
|
||||
|
||||
// Networks with tokens
|
||||
ETHEREUM(100, "ETH", "Ethereum"),
|
||||
ETHEREUM_CLASSIC(101, "ETC", "Ethereum Classic"),
|
||||
FANTOM(
|
||||
102,
|
||||
"FTM",
|
||||
"Fantom"
|
||||
), // LIGHTNING(1001, "BTC_LN", "Bitcoin Lightning"),
|
||||
POLYGON(1002, "POLYGON", "Polygon Matic"),
|
||||
RSK(1003, "RSK", "Bitcoin RSK"),
|
||||
ARBITRUM(
|
||||
1004,
|
||||
"ARBITRUM",
|
||||
"Arbitrum"
|
||||
),
|
||||
OPTIMISM(1005, "OPTIMISM", "Optimism"),
|
||||
BSC(1006, "BSC", "Binance Smart Chain"), // Testnets
|
||||
TESTNET_MORDEN(10001, "MORDEN", "Morden Testnet"),
|
||||
TESTNET_KOVAN(10002, "KOVAN", "Kovan Testnet"),
|
||||
TESTNET_BITCOIN(
|
||||
10003,
|
||||
"TESTNET_BITCOIN",
|
||||
"Bitcoin Testnet"
|
||||
), // TESTNET_FLOONET(10004, "FLOONET", "Floonet Testnet"),
|
||||
TESTNET_GOERLI(10005, "GOERLI", "Goerli Testnet"),
|
||||
TESTNET_ROPSTEN(
|
||||
10006,
|
||||
"ROPSTEN",
|
||||
"Ropsten Testnet"
|
||||
),
|
||||
TESTNET_RINKEBY(10007, "RINKEBY", "Rinkeby Testnet");
|
||||
|
||||
companion object {
|
||||
fun byId(id: Int): Chain {
|
||||
for (chain in values()) {
|
||||
if (chain.id == id) {
|
||||
return chain
|
||||
}
|
||||
}
|
||||
return UNSPECIFIED
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package io.emeraldpay.dshackle
|
||||
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import java.util.EnumMap
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
@@ -33,9 +33,11 @@ import org.springframework.boot.SpringApplication
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Profile
|
||||
import org.springframework.core.env.Environment
|
||||
import org.springframework.scheduling.annotation.EnableAsync
|
||||
import org.springframework.scheduling.annotation.EnableScheduling
|
||||
import org.springframework.util.ResourceUtils
|
||||
import reactor.core.scheduler.Scheduler
|
||||
import reactor.core.scheduler.Schedulers
|
||||
import java.io.File
|
||||
@@ -47,8 +49,8 @@ import kotlin.system.exitProcess
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
open class Config(
|
||||
@Autowired private val env: Environment,
|
||||
@Autowired private val ctx: ApplicationContext
|
||||
private val env: Environment,
|
||||
private val ctx: ApplicationContext
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -61,7 +63,12 @@ open class Config(
|
||||
private var configFilePath: File? = null
|
||||
|
||||
init {
|
||||
configFilePath = getConfigPath()
|
||||
configFilePath = if (env.activeProfiles.contains("integration-test")) {
|
||||
ResourceUtils.getFile("classpath:integration/dshackle.yaml")
|
||||
} else {
|
||||
getConfigPath()
|
||||
}
|
||||
|
||||
Global.version = env.getProperty("version.app", Global.version).let {
|
||||
if (it.contains("SNAPSHOT")) {
|
||||
listOfNotNull(it, env.getProperty("version.commit")).joinToString("-")
|
||||
@@ -95,6 +102,7 @@ open class Config(
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Profile("!integration-test")
|
||||
open fun mainConfig(@Autowired fileResolver: FileResolver): MainConfig {
|
||||
val f = configFilePath ?: throw IllegalStateException("Config path is not set")
|
||||
log.info("Using config: ${f.absolutePath}")
|
||||
|
||||
@@ -27,7 +27,6 @@ import io.emeraldpay.dshackle.upstream.bitcoin.data.RpcUnspent
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.data.RpcUnspentDeserializer
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package io.emeraldpay.dshackle
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
/**
|
||||
* Exception that should be handled/logged without a stacktrace in production
|
||||
|
||||
@@ -20,12 +20,10 @@ import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.ResourceBanner
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import org.springframework.core.io.support.ResourcePropertySource
|
||||
|
||||
@SpringBootApplication(scanBasePackages = ["io.emeraldpay.dshackle"])
|
||||
@Import(Config::class)
|
||||
open class Starter
|
||||
|
||||
private val log = LoggerFactory.getLogger(Starter::class.java)
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.data.TxId
|
||||
import io.emeraldpay.dshackle.proto.CachesProto
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.api.reactive.RedisReactiveCommands
|
||||
import org.slf4j.LoggerFactory
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.CacheConfig
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.RedisClient
|
||||
import io.lettuce.core.RedisConnectionException
|
||||
import io.lettuce.core.RedisURI
|
||||
@@ -42,7 +42,7 @@ open class CachesFactory(
|
||||
}
|
||||
|
||||
private var redis: StatefulRedisConnection<String, ByteArray>? = null
|
||||
private val all = EnumMap<Chain, Caches>(io.emeraldpay.grpc.Chain::class.java)
|
||||
private val all = EnumMap<Chain, Caches>(Chain::class.java)
|
||||
|
||||
@PostConstruct
|
||||
fun init() {
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.api.reactive.RedisReactiveCommands
|
||||
import org.slf4j.LoggerFactory
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.proto.CachesProto
|
||||
import io.emeraldpay.dshackle.proto.CachesProto.ValueContainer
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.api.reactive.RedisReactiveCommands
|
||||
import org.slf4j.LoggerFactory
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.TxId
|
||||
import io.emeraldpay.dshackle.proto.CachesProto
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.api.reactive.RedisReactiveCommands
|
||||
import org.slf4j.LoggerFactory
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.DefaultContainer
|
||||
import io.emeraldpay.dshackle.proto.CachesProto
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionReceiptJson
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.api.reactive.RedisReactiveCommands
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
package io.emeraldpay.dshackle.cache
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.data.TxContainer
|
||||
import io.emeraldpay.dshackle.data.TxId
|
||||
import io.emeraldpay.dshackle.proto.CachesProto
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.lettuce.core.api.reactive.RedisReactiveCommands
|
||||
import org.slf4j.LoggerFactory
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.config
|
||||
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
|
||||
class HealthConfig {
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.config
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.yaml.snakeyaml.nodes.CollectionNode
|
||||
import org.yaml.snakeyaml.nodes.MappingNode
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.config
|
||||
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
|
||||
/**
|
||||
* Configure HTTP Proxy to Upstreams
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.config
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.yaml.snakeyaml.nodes.MappingNode
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.config
|
||||
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
class TokensConfig(
|
||||
val tokens: List<Token>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package io.emeraldpay.dshackle.config.context
|
||||
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.CachesFactory
|
||||
import io.emeraldpay.dshackle.upstream.CallTargetsHolder
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@Configuration
|
||||
open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) {
|
||||
@Bean
|
||||
open fun allMultistreams(
|
||||
cachesFactory: CachesFactory,
|
||||
callTargetsHolder: CallTargetsHolder
|
||||
): List<Multistream> {
|
||||
return Chain.values()
|
||||
.filterNot { it == Chain.UNSPECIFIED }
|
||||
.mapNotNull { chain ->
|
||||
when (BlockchainType.from(chain)) {
|
||||
BlockchainType.EVM_POS -> ethereumPosMultistream(chain, cachesFactory)
|
||||
BlockchainType.EVM_POW -> ethereumMultistream(chain, cachesFactory)
|
||||
BlockchainType.BITCOIN -> bitcoinMultistream(chain, cachesFactory)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ethereumMultistream(
|
||||
chain: Chain,
|
||||
cachesFactory: CachesFactory
|
||||
): EthereumMultistream {
|
||||
val name = "multi-ethereum-$chain"
|
||||
|
||||
return EthereumMultistream(
|
||||
chain,
|
||||
ArrayList(),
|
||||
cachesFactory.getCaches(chain)
|
||||
).also { register(it, name) }
|
||||
}
|
||||
|
||||
open fun ethereumPosMultistream(
|
||||
chain: Chain,
|
||||
cachesFactory: CachesFactory
|
||||
): EthereumPosMultiStream {
|
||||
val name = "multi-ethereum-pos-$chain"
|
||||
|
||||
return EthereumPosMultiStream(
|
||||
chain,
|
||||
ArrayList(),
|
||||
cachesFactory.getCaches(chain)
|
||||
).also { register(it, name) }
|
||||
}
|
||||
|
||||
open fun bitcoinMultistream(
|
||||
chain: Chain,
|
||||
cachesFactory: CachesFactory
|
||||
): BitcoinMultistream {
|
||||
val name = "multi-bitcoin-$chain"
|
||||
|
||||
return BitcoinMultistream(
|
||||
chain,
|
||||
ArrayList(),
|
||||
cachesFactory.getCaches(chain)
|
||||
).also { register(it, name) }
|
||||
}
|
||||
|
||||
private fun register(bean: Any, name: String) {
|
||||
beanFactory.initializeBean(bean, name)
|
||||
beanFactory.autowireBean(bean)
|
||||
this.beanFactory.registerSingleton(name, bean)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.emeraldpay.dshackle.monitoring.accesslog
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.MainConfig
|
||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package io.emeraldpay.dshackle.monitoring.accesslog
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@@ -17,8 +17,8 @@ package io.emeraldpay.dshackle.monitoring.accesslog
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.AccessLogConfig
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.Attributes
|
||||
import io.grpc.Grpc
|
||||
import io.grpc.Metadata
|
||||
|
||||
@@ -17,9 +17,9 @@ package io.emeraldpay.dshackle.proxy
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.reactivestreams.Publisher
|
||||
import org.slf4j.LoggerFactory
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.proxy
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.config.ProxyConfig
|
||||
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.Unpooled
|
||||
import org.reactivestreams.Publisher
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.proxy
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.TlsSetup
|
||||
import io.emeraldpay.dshackle.config.ProxyConfig
|
||||
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||
import io.emeraldpay.dshackle.rpc.NativeSubscribe
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import io.micrometer.core.instrument.Timer
|
||||
|
||||
@@ -18,6 +18,7 @@ package io.emeraldpay.dshackle.proxy
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass.Selector
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.config.ProxyConfig
|
||||
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
||||
@@ -25,7 +26,6 @@ import io.emeraldpay.dshackle.rpc.NativeCall
|
||||
import io.emeraldpay.dshackle.rpc.NativeSubscribe
|
||||
import io.emeraldpay.etherjar.rpc.json.RequestJson
|
||||
import io.emeraldpay.etherjar.rpc.json.ResponseJson
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.netty.buffer.ByteBufInputStream
|
||||
import io.netty.buffer.Unpooled
|
||||
import org.reactivestreams.Publisher
|
||||
|
||||
@@ -19,9 +19,9 @@ package io.emeraldpay.dshackle.rpc
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.ChainValue
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import io.micrometer.core.instrument.Timer
|
||||
|
||||
@@ -44,6 +44,7 @@ class Describe(
|
||||
.setChain(Common.ChainRef.forNumber(chain.id))
|
||||
.addAllSupportedMethods(targets)
|
||||
.setStatus(status)
|
||||
.setCurrentHeight(chainUpstreams.getHead().getCurrentHeight() ?: 0)
|
||||
chainUpstreams.getAll().let { ups ->
|
||||
ups.forEach { up ->
|
||||
val nodes = QuorumForLabels()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.upstream.ChainFees
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusException
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@@ -19,6 +19,8 @@ package io.emeraldpay.dshackle.rpc
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||
@@ -26,11 +28,11 @@ import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
|
||||
import io.emeraldpay.dshackle.quorum.QuorumReaderFactory
|
||||
import io.emeraldpay.dshackle.quorum.QuorumRpcReader
|
||||
import io.emeraldpay.dshackle.startup.ConfiguredUpstreams
|
||||
import io.emeraldpay.dshackle.upstream.ApiSource
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.EthereumCallSelector
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError
|
||||
@@ -40,12 +42,10 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||
import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.event.EventListener
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
@@ -55,9 +55,9 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
@Service
|
||||
open class NativeCall(
|
||||
@Autowired private val multistreamHolder: MultistreamHolder,
|
||||
@Autowired private val configuredUpstreams: ConfiguredUpstreams,
|
||||
@Autowired private val signer: ResponseSigner
|
||||
private val multistreamHolder: MultistreamHolder,
|
||||
private val configuredUpstreams: ConfiguredUpstreams,
|
||||
private val signer: ResponseSigner
|
||||
) {
|
||||
|
||||
private val log = LoggerFactory.getLogger(NativeCall::class.java)
|
||||
@@ -66,18 +66,19 @@ open class NativeCall(
|
||||
var quorumReaderFactory: QuorumReaderFactory = QuorumReaderFactory.default()
|
||||
private val ethereumCallSelectors = EnumMap<Chain, EthereumCallSelector>(Chain::class.java)
|
||||
|
||||
init {
|
||||
val casting = mapOf(
|
||||
companion object {
|
||||
val casting: Map<BlockchainType, Class<out EthereumLikeMultistream>> = mapOf(
|
||||
BlockchainType.EVM_POS to EthereumPosMultiStream::class.java,
|
||||
BlockchainType.EVM_POW to EthereumMultistream::class.java,
|
||||
BlockchainType.EVM_POW to EthereumMultistream::class.java
|
||||
)
|
||||
}
|
||||
|
||||
multistreamHolder.observeChains().subscribe { chain ->
|
||||
casting[BlockchainType.from(chain)]?.let { cast ->
|
||||
multistreamHolder.getUpstream(chain)?.let { up ->
|
||||
val reader = up.cast(cast).getReader()
|
||||
ethereumCallSelectors.putIfAbsent(chain, EthereumCallSelector(reader.heightByHash()))
|
||||
}
|
||||
@EventListener
|
||||
fun onUpstreamChangeEvent(event: UpstreamChangeEvent) {
|
||||
casting[BlockchainType.from(event.chain)]?.let { cast ->
|
||||
multistreamHolder.getUpstream(event.chain)?.let { up ->
|
||||
val reader = up.cast(cast).getReader()
|
||||
ethereumCallSelectors.putIfAbsent(event.chain, EthereumCallSelector(reader.heightByHash()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +167,8 @@ open class NativeCall(
|
||||
}
|
||||
|
||||
val matcher = Selector.convertToMatcher(request.selector)
|
||||
if (!configuredUpstreams.hasMatchingUpstream(chain, matcher)) {
|
||||
|
||||
if (!multistreamHolder.getUpstream(chain).hasMatchingUpstream(matcher)) {
|
||||
if (Global.metricsExtended) {
|
||||
Metrics.globalRegistry
|
||||
.counter("no_matching_upstream", "chain", chain.chainCode, "matcher", matcher.describeInternal())
|
||||
@@ -176,7 +178,6 @@ open class NativeCall(
|
||||
}
|
||||
|
||||
val upstream = multistreamHolder.getUpstream(chain)
|
||||
?: return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(chain)))
|
||||
|
||||
return prepareCall(request, upstream)
|
||||
}
|
||||
@@ -255,17 +256,13 @@ open class NativeCall(
|
||||
}
|
||||
|
||||
private fun getRequestDecorator(method: String): RequestDecorator =
|
||||
if (method in listOf(
|
||||
"eth_getFilterChanges",
|
||||
"eth_uninstallFilter",
|
||||
)
|
||||
)
|
||||
GetFilterUpdatesDecorator()
|
||||
if (method in DefaultEthereumMethods.withFilterIdMethods)
|
||||
WithFilterIdDecorator()
|
||||
else
|
||||
NoneRequestDecorator()
|
||||
|
||||
private fun getResultDecorator(method: String): ResultDecorator =
|
||||
if (CreateFilterDecorator.createFilterMethods.contains(method)) CreateFilterDecorator() else NoneResultDecorator()
|
||||
if (method in DefaultEthereumMethods.newFilterMethods) CreateFilterDecorator() else NoneResultDecorator()
|
||||
|
||||
fun fetch(ctx: ValidCallContext<ParsedCallDetails>): Mono<CallResult> {
|
||||
return ctx.upstream.getRoutedApi(ctx.matcher)
|
||||
@@ -385,11 +382,6 @@ open class NativeCall(
|
||||
|
||||
companion object {
|
||||
const val quoteCode = '"'.code.toByte()
|
||||
val createFilterMethods = listOf(
|
||||
"eth_newFilter",
|
||||
"eth_newBlockFilter",
|
||||
"eth_newPendingTransactionFilter",
|
||||
)
|
||||
}
|
||||
override fun processResult(result: QuorumRpcReader.Result): ByteArray {
|
||||
val bytes = result.value
|
||||
@@ -410,7 +402,7 @@ open class NativeCall(
|
||||
override fun processRequest(request: List<Any>): List<Any> = request
|
||||
}
|
||||
|
||||
open class GetFilterUpdatesDecorator : RequestDecorator {
|
||||
open class WithFilterIdDecorator : RequestDecorator {
|
||||
override fun processRequest(request: List<Any>): List<Any> {
|
||||
val filterId = request.first().toString()
|
||||
val sanitized = filterId.substring(0, filterId.lastIndex - 1)
|
||||
|
||||
@@ -18,6 +18,8 @@ package io.emeraldpay.dshackle.rpc
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass.NativeSubscribeReplyItem
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
@@ -25,8 +27,6 @@ import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.HasUpstream
|
||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusException
|
||||
import org.reactivestreams.Publisher
|
||||
|
||||
@@ -19,9 +19,9 @@ package io.emeraldpay.dshackle.rpc
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -18,10 +18,10 @@ package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,27 +18,28 @@ package io.emeraldpay.dshackle.rpc
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||
import io.emeraldpay.dshackle.upstream.Capability
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.data.SimpleUnspent
|
||||
import io.emeraldpay.dshackle.upstream.grpc.BitcoinGrpcUpstream
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.bitcoinj.params.MainNetParams
|
||||
import org.bitcoinj.params.TestNet3Params
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.event.EventListener
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.math.BigInteger
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.annotation.PostConstruct
|
||||
|
||||
@Service
|
||||
class TrackBitcoinAddress(
|
||||
@@ -67,15 +68,13 @@ class TrackBitcoinAddress(
|
||||
Selector.CapabilityMatcher(Capability.BALANCE)
|
||||
)
|
||||
|
||||
@PostConstruct
|
||||
fun listenChains() {
|
||||
multistreamHolder.observeChains().subscribe { chain ->
|
||||
multistreamHolder.getUpstream(chain)?.let { mup ->
|
||||
val available = mup.getAll().any { up ->
|
||||
!up.isGrpc() && up.getCapabilities().contains(Capability.BALANCE)
|
||||
}
|
||||
setBalanceAvailability(chain, available)
|
||||
@EventListener
|
||||
fun onUpstreamChangeEvent(event: UpstreamChangeEvent) {
|
||||
multistreamHolder.getUpstream(event.chain)?.let { mup ->
|
||||
val available = mup.getAll().any { up ->
|
||||
!up.isGrpc() && up.getCapabilities().contains(Capability.BALANCE)
|
||||
}
|
||||
setBalanceAvailability(event.chain, available)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.ExtractBlock
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -17,6 +17,8 @@ package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.config.TokensConfig
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
@@ -26,8 +28,6 @@ import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.etherjar.domain.EventId
|
||||
import io.emeraldpay.etherjar.erc20.ERC20Token
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -18,14 +18,14 @@ package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.etherjar.domain.Wei
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -18,6 +18,8 @@ package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.SilentException
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.TxId
|
||||
@@ -29,8 +31,6 @@ import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.etherjar.rpc.json.BlockJson
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionJson
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
interface TrackTx {
|
||||
|
||||
@@ -17,17 +17,13 @@
|
||||
package io.emeraldpay.dshackle.startup
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.FileResolver
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.CurrentMultistreamHolder
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.HttpRpcFactory
|
||||
import io.emeraldpay.dshackle.upstream.MergedHead
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinRpcHead
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinZMQHead
|
||||
@@ -47,31 +43,30 @@ import io.emeraldpay.dshackle.upstream.forkchoice.NoChoiceWithPriorityForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstreams
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Repository
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.stereotype.Component
|
||||
import java.net.URI
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.function.Function
|
||||
import javax.annotation.PostConstruct
|
||||
import kotlin.math.abs
|
||||
|
||||
@Repository
|
||||
@Component
|
||||
open class ConfiguredUpstreams(
|
||||
@Autowired private val currentUpstreams: CurrentMultistreamHolder,
|
||||
@Autowired private val fileResolver: FileResolver,
|
||||
@Autowired private val config: UpstreamsConfig
|
||||
) {
|
||||
private val fileResolver: FileResolver,
|
||||
private val config: UpstreamsConfig,
|
||||
private val callTargets: CallTargetsHolder,
|
||||
private val eventPublisher: ApplicationEventPublisher
|
||||
) : ApplicationRunner {
|
||||
|
||||
private val log = LoggerFactory.getLogger(ConfiguredUpstreams::class.java)
|
||||
private var seq = AtomicInteger(0)
|
||||
|
||||
private val hashes: MutableMap<Byte, Boolean> = HashMap()
|
||||
|
||||
@PostConstruct
|
||||
fun start() {
|
||||
override fun run(args: ApplicationArguments) {
|
||||
log.debug("Starting upstreams")
|
||||
val defaultOptions = buildDefaultOptions(config)
|
||||
config.upstreams.forEach { up ->
|
||||
@@ -115,17 +110,13 @@ open class ConfiguredUpstreams(
|
||||
}
|
||||
}
|
||||
upstream?.let {
|
||||
currentUpstreams.update(UpstreamChange(chain, upstream, UpstreamChange.ChangeType.ADDED))
|
||||
val event = UpstreamChangeEvent(chain, upstream, UpstreamChangeEvent.ChangeType.ADDED)
|
||||
eventPublisher.publishEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasMatchingUpstream(chain: Chain, matcher: Selector.LabelSelectorMatcher): Boolean =
|
||||
config.upstreams.any { up ->
|
||||
(up.chain?.let { Global.chainById(it) == chain } ?: true) && matcher.matches(up.labels)
|
||||
}
|
||||
|
||||
private fun buildDefaultOptions(config: UpstreamsConfig): HashMap<Chain, UpstreamsConfig.Options> {
|
||||
val defaultOptions = HashMap<Chain, UpstreamsConfig.Options>()
|
||||
config.defaultOptions.forEach { defaultsConfig ->
|
||||
@@ -150,7 +141,7 @@ open class ConfiguredUpstreams(
|
||||
fun buildMethods(config: UpstreamsConfig.Upstream<*>, chain: Chain): CallMethods {
|
||||
return if (config.methods != null) {
|
||||
ManagedCallMethods(
|
||||
currentUpstreams.getDefaultMethods(chain),
|
||||
callTargets.getDefaultMethods(chain),
|
||||
config.methods!!.enabled.map { it.name }.toSet(),
|
||||
config.methods!!.disabled.map { it.name }.toSet()
|
||||
).also {
|
||||
@@ -164,7 +155,7 @@ open class ConfiguredUpstreams(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentUpstreams.getDefaultMethods(chain)
|
||||
callTargets.getDefaultMethods(chain)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +306,7 @@ open class ConfiguredUpstreams(
|
||||
.doOnNext {
|
||||
log.info("Chain ${it.chain} ${it.type} through gRPC at ${endpoint.host}:${endpoint.port}. With caps: ${it.upstream.getCapabilities()}")
|
||||
}
|
||||
.subscribe(currentUpstreams::update)
|
||||
.subscribe(eventPublisher::publishEvent)
|
||||
}
|
||||
|
||||
private fun buildHttpFactory(conn: UpstreamsConfig.RpcConnection, urls: ArrayList<URI>? = null): HttpRpcFactory? {
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.startup
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
/**
|
||||
* An update event to the list of currently available upstreams.
|
||||
*/
|
||||
class UpstreamChange(
|
||||
class UpstreamChangeEvent(
|
||||
/**
|
||||
* Target blockchain
|
||||
*/
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultBitcoinMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.HashMap
|
||||
|
||||
@Component
|
||||
class CallTargetsHolder {
|
||||
private val callTargets = HashMap<Chain, CallMethods>()
|
||||
|
||||
fun getDefaultMethods(chain: Chain): CallMethods {
|
||||
return callTargets[chain] ?: return setupDefaultMethods(chain)
|
||||
}
|
||||
|
||||
private fun setupDefaultMethods(chain: Chain): CallMethods {
|
||||
val created = when (BlockchainType.from(chain)) {
|
||||
BlockchainType.EVM_POW -> DefaultEthereumMethods(chain)
|
||||
BlockchainType.BITCOIN -> DefaultBitcoinMethods()
|
||||
BlockchainType.EVM_POS -> DefaultEthereumMethods(chain)
|
||||
else -> throw IllegalStateException("Unsupported chain: $chain")
|
||||
}
|
||||
callTargets[chain] = created
|
||||
return created
|
||||
}
|
||||
}
|
||||
@@ -16,156 +16,40 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.cache.CachesFactory
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChange
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultBitcoinMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.grpc.BlockchainType
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Repository
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Sinks
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import org.springframework.stereotype.Component
|
||||
import javax.annotation.PreDestroy
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
@Repository
|
||||
@Component
|
||||
open class CurrentMultistreamHolder(
|
||||
@Autowired private val cachesFactory: CachesFactory
|
||||
multistreams: List<Multistream>
|
||||
) : MultistreamHolder {
|
||||
|
||||
private val log = LoggerFactory.getLogger(CurrentMultistreamHolder::class.java)
|
||||
|
||||
private val chainMapping = ConcurrentHashMap<Chain, Multistream>()
|
||||
private val chainsBus = Sinks.many()
|
||||
.multicast()
|
||||
.directBestEffort<Chain>()
|
||||
private val callTargets = HashMap<Chain, CallMethods>()
|
||||
private val updateLock = ReentrantLock()
|
||||
private val chainMapping = multistreams.associateBy { it.chain }
|
||||
|
||||
fun update(change: UpstreamChange) {
|
||||
updateLock.withLock {
|
||||
log.debug("Upstream update: ${change.type} ${change.chain} via ${change.upstream.getId()}")
|
||||
val chain = change.chain
|
||||
try {
|
||||
when (BlockchainType.from(chain)) {
|
||||
BlockchainType.EVM_POW -> {
|
||||
val up = change.upstream.cast(EthereumUpstream::class.java)
|
||||
val current = chainMapping[chain]
|
||||
val factory = Callable<Multistream> {
|
||||
EthereumMultistream(chain, ArrayList(), cachesFactory.getCaches(chain))
|
||||
}
|
||||
processUpdate(change, up, current, factory)
|
||||
}
|
||||
BlockchainType.EVM_POS -> {
|
||||
val up = change.upstream.cast(EthereumPosUpstream::class.java)
|
||||
val current = chainMapping[chain]
|
||||
val factory = Callable<Multistream> {
|
||||
EthereumPosMultiStream(chain, ArrayList(), cachesFactory.getCaches(chain))
|
||||
}
|
||||
processUpdate(change, up, current, factory)
|
||||
}
|
||||
BlockchainType.BITCOIN -> {
|
||||
val up = change.upstream.cast(BitcoinUpstream::class.java)
|
||||
val current = chainMapping[chain]
|
||||
val factory = Callable<Multistream> {
|
||||
BitcoinMultistream(chain, ArrayList(), cachesFactory.getCaches(chain))
|
||||
}
|
||||
processUpdate(change, up, current, factory)
|
||||
}
|
||||
else -> {
|
||||
log.error("Update for unsupported chain: $chain")
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
log.error("Failed to update upstream", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun processUpdate(change: UpstreamChange, up: Upstream, current: Multistream?, factory: Callable<Multistream>) {
|
||||
val chain = change.chain
|
||||
if (change.type == UpstreamChange.ChangeType.REMOVED) {
|
||||
current?.removeUpstream(up.getId())
|
||||
log.info("Upstream ${change.upstream.getId()} with chain $chain has been removed")
|
||||
} else {
|
||||
if (current == null) {
|
||||
val created = factory.call()
|
||||
if (up is CachesEnabled) {
|
||||
up.setCaches(created.caches)
|
||||
}
|
||||
created.addUpstream(up)
|
||||
created.start()
|
||||
chainMapping[chain] = created
|
||||
chainsBus.tryEmitNext(chain)
|
||||
} else {
|
||||
if (up is CachesEnabled) {
|
||||
up.setCaches(current.caches)
|
||||
}
|
||||
current.addUpstream(up)
|
||||
}
|
||||
if (!callTargets.containsKey(chain)) {
|
||||
setupDefaultMethods(chain)
|
||||
}
|
||||
log.info("Upstream ${change.upstream.getId()} with chain $chain has been added")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUpstream(chain: Chain): Multistream? {
|
||||
return chainMapping[chain]
|
||||
override fun getUpstream(chain: Chain): Multistream {
|
||||
return chainMapping.getValue(chain)
|
||||
}
|
||||
|
||||
override fun getAvailable(): List<Chain> {
|
||||
return Collections.unmodifiableList(chainMapping.keys.toList())
|
||||
}
|
||||
|
||||
override fun observeChains(): Flux<Chain> {
|
||||
return Flux.concat(
|
||||
Flux.fromIterable(getAvailable()),
|
||||
chainsBus.asFlux()
|
||||
)
|
||||
}
|
||||
|
||||
override fun getDefaultMethods(chain: Chain): CallMethods {
|
||||
return callTargets[chain] ?: return setupDefaultMethods(chain)
|
||||
}
|
||||
|
||||
fun setupDefaultMethods(chain: Chain): CallMethods {
|
||||
val created = when (BlockchainType.from(chain)) {
|
||||
BlockchainType.EVM_POW -> DefaultEthereumMethods(chain)
|
||||
BlockchainType.BITCOIN -> DefaultBitcoinMethods()
|
||||
BlockchainType.EVM_POS -> DefaultEthereumMethods(chain)
|
||||
else -> throw IllegalStateException("Unsupported chain: $chain")
|
||||
}
|
||||
callTargets[chain] = created
|
||||
return created
|
||||
return chainMapping.values.asSequence()
|
||||
.filter { it.haveUpstreams() }
|
||||
.map { it.chain }
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun isAvailable(chain: Chain): Boolean {
|
||||
return chainMapping.containsKey(chain) && callTargets.containsKey(chain)
|
||||
return chainMapping.getValue(chain).isAvailable()
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
fun shutdown() {
|
||||
log.info("Closing upstream connections...")
|
||||
updateLock.withLock {
|
||||
chainMapping.values.forEach {
|
||||
it.stop()
|
||||
}
|
||||
chainMapping.clear()
|
||||
chainMapping.values.forEach {
|
||||
it.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.DistributionSummary
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import io.micrometer.core.instrument.Tag
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
interface HttpFactory {
|
||||
fun create(id: String?, chain: Chain): Reader<JsonRpcRequest, JsonRpcResponse>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.AuthConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcHttpClient
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.RpcMetrics
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import io.micrometer.core.instrument.Tag
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
interface Lifecycle {
|
||||
fun start()
|
||||
fun stop()
|
||||
fun isRunning(): Boolean
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
@@ -43,7 +42,7 @@ class MergedHead(
|
||||
override fun start() {
|
||||
super.start()
|
||||
sources.forEach { head ->
|
||||
if (head is Lifecycle && !head.isRunning) {
|
||||
if (head is Lifecycle && !head.isRunning()) {
|
||||
head.start()
|
||||
}
|
||||
}
|
||||
@@ -56,7 +55,7 @@ class MergedHead(
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
sources.forEach { head ->
|
||||
if (head is Lifecycle && head.isRunning) {
|
||||
if (head is Lifecycle && head.isRunning()) {
|
||||
head.stop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,26 +16,30 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import io.micrometer.core.instrument.Tag
|
||||
import org.apache.commons.collections4.Factory
|
||||
import org.apache.commons.collections4.FunctorException
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import org.springframework.context.event.EventListener
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.Locale
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import java.util.function.Predicate
|
||||
@@ -56,6 +60,8 @@ abstract class Multistream(
|
||||
private const val metrics = "upstreams"
|
||||
}
|
||||
|
||||
private var started = false
|
||||
|
||||
private var cacheSubscription: Disposable? = null
|
||||
private val reconfigLock = ReentrantLock()
|
||||
private var callMethods: CallMethods? = null
|
||||
@@ -231,6 +237,7 @@ abstract class Multistream(
|
||||
// print status _change_ every 15 seconds, at most; otherwise prints it on interval of 30 seconds
|
||||
.sample(Duration.ofSeconds(15))
|
||||
.subscribe { printStatus() }
|
||||
started = true
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
@@ -244,6 +251,7 @@ abstract class Multistream(
|
||||
}
|
||||
}
|
||||
lagObserver?.stop()
|
||||
started = false
|
||||
}
|
||||
|
||||
fun onHeadUpdated(head: Head) {
|
||||
@@ -316,6 +324,38 @@ abstract class Multistream(
|
||||
log.info("State of ${chain.chainCode}: height=${height ?: '?'}, status=[$statuses], lag=[$lag], weak=[$weak]")
|
||||
}
|
||||
|
||||
fun test(event: UpstreamChangeEvent): Boolean {
|
||||
return event.chain == this.chain
|
||||
}
|
||||
|
||||
@EventListener
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
fun onUpstreamChange(event: UpstreamChangeEvent) {
|
||||
val chain = event.chain
|
||||
if (this.chain == chain) {
|
||||
if (event.type == UpstreamChangeEvent.ChangeType.REMOVED) {
|
||||
removeUpstream(event.upstream.getId())
|
||||
log.error("Upstream ${event.upstream.getId()} with chain $chain has been removed")
|
||||
} else {
|
||||
if (event.upstream is CachesEnabled) {
|
||||
event.upstream.setCaches(caches)
|
||||
}
|
||||
addUpstream(event.upstream)
|
||||
if (!started) {
|
||||
start()
|
||||
}
|
||||
log.error("Upstream ${event.upstream.getId()} with chain $chain has been added")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun haveUpstreams(): Boolean =
|
||||
upstreams.isNotEmpty()
|
||||
|
||||
fun hasMatchingUpstream(matcher: Selector.LabelSelectorMatcher): Boolean {
|
||||
return upstreams.any { matcher.matches(it) }
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
|
||||
class UpstreamStatus(val upstream: Upstream, val status: UpstreamAvailability, val ts: Instant = Instant.now())
|
||||
|
||||
@@ -16,17 +16,13 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import reactor.core.publisher.Flux
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
|
||||
/**
|
||||
* Holds Multistreams configured for a chain.
|
||||
*/
|
||||
interface MultistreamHolder {
|
||||
fun getUpstream(chain: Chain): Multistream?
|
||||
fun getUpstream(chain: Chain): Multistream
|
||||
fun getAvailable(): List<Chain>
|
||||
fun observeChains(): Flux<Chain>
|
||||
fun getDefaultMethods(chain: Chain): CallMethods
|
||||
fun isAvailable(chain: Chain): Boolean
|
||||
}
|
||||
|
||||
@@ -15,24 +15,17 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.ChainFees
|
||||
import io.emeraldpay.dshackle.upstream.EmptyHead
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.MergedHead
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.RequestPostprocessor
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultBitcoinMethods
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -142,7 +135,7 @@ open class BitcoinMultistream(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return super.isRunning() || reader.isRunning
|
||||
return super.isRunning() || reader.isRunning()
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
|
||||
@@ -19,13 +19,13 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.upstream.Capability
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.data.SimpleUnspent
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.bitcoinj.core.Address
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.kotlin.core.publisher.cast
|
||||
|
||||
@@ -72,7 +72,7 @@ open class BitcoinReader(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return mempool.isRunning
|
||||
return mempool.isRunning()
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
|
||||
@@ -19,11 +19,11 @@ import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.AbstractHead
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
@@ -15,19 +15,19 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.Capability
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
|
||||
open class BitcoinRpcUpstream(
|
||||
@@ -92,7 +92,7 @@ open class BitcoinRpcUpstream(
|
||||
override fun isRunning(): Boolean {
|
||||
var runningAny = validatorSubscription != null
|
||||
if (head is Lifecycle) {
|
||||
runningAny = runningAny || head.isRunning
|
||||
runningAny = runningAny || head.isRunning()
|
||||
}
|
||||
return runningAny
|
||||
}
|
||||
@@ -100,7 +100,7 @@ open class BitcoinRpcUpstream(
|
||||
override fun start() {
|
||||
log.info("Configured for ${chain.chainName}")
|
||||
if (head is Lifecycle) {
|
||||
if (!head.isRunning) {
|
||||
if (!head.isRunning()) {
|
||||
head.start()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultBitcoinMethods
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
abstract class BitcoinUpstream(
|
||||
|
||||
@@ -5,12 +5,12 @@ import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.AbstractHead
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
@@ -65,6 +65,6 @@ class BitcoinZMQHead(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return server.isRunning || refreshSubscription != null
|
||||
return server.isRunning() || refreshSubscription != null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ package io.emeraldpay.dshackle.upstream.bitcoin
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Mono
|
||||
import java.time.Duration
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import org.zeromq.SocketType
|
||||
import org.zeromq.ZContext
|
||||
import org.zeromq.ZMQ
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.quorum.BroadcastQuorum
|
||||
@@ -23,7 +24,6 @@ import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||
import io.emeraldpay.dshackle.quorum.NonceQuorum
|
||||
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
|
||||
import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
/**
|
||||
* Default configuration for Ethereum based RPC. Defines optimal Quorum strategies for different methods, and provides
|
||||
@@ -35,6 +35,20 @@ class DefaultEthereumMethods(
|
||||
|
||||
private val version = "\"EmeraldDshackle/${Global.version}\""
|
||||
|
||||
companion object {
|
||||
val withFilterIdMethods = listOf(
|
||||
"eth_getFilterChanges",
|
||||
"eth_getFilterLogs",
|
||||
"eth_uninstallFilter"
|
||||
)
|
||||
|
||||
val newFilterMethods = listOf(
|
||||
"eth_newFilter",
|
||||
"eth_newBlockFilter",
|
||||
"eth_newPendingTransactionFilter",
|
||||
)
|
||||
}
|
||||
|
||||
private val anyResponseMethods = listOf(
|
||||
"eth_gasPrice",
|
||||
"eth_call",
|
||||
@@ -70,13 +84,7 @@ class DefaultEthereumMethods(
|
||||
"eth_feeHistory"
|
||||
)
|
||||
|
||||
private val filterMethods = listOf(
|
||||
"eth_getFilterChanges",
|
||||
"eth_newFilter",
|
||||
"eth_newBlockFilter",
|
||||
"eth_newPendingTransactionFilter",
|
||||
"eth_uninstallFilter"
|
||||
)
|
||||
private val filterMethods = withFilterIdMethods + newFilterMethods
|
||||
|
||||
private val hardcodedMethods = listOf(
|
||||
"net_version",
|
||||
|
||||
@@ -57,7 +57,7 @@ class EthereumCallSelector(
|
||||
return blockTagSelector(params, 1, head)
|
||||
} else if (method == "eth_getStorageAt") {
|
||||
return blockTagSelector(params, 2, head)
|
||||
} else if (method == "eth_getFilterChanges" || method == "eth_uninstallFilter") {
|
||||
} else if (method in DefaultEthereumMethods.withFilterIdMethods) {
|
||||
return sameUpstreamMatcher(params)
|
||||
}
|
||||
return Mono.empty()
|
||||
|
||||
@@ -17,23 +17,17 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.ChainFees
|
||||
import io.emeraldpay.dshackle.upstream.EmptyHead
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.MergedHead
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import org.springframework.util.ConcurrentReferenceHashMap
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
@@ -85,7 +79,7 @@ open class EthereumMultistream(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return super.isRunning() || reader.isRunning
|
||||
return super.isRunning() || reader.isRunning()
|
||||
}
|
||||
|
||||
override fun getReader(): EthereumReader {
|
||||
|
||||
@@ -30,6 +30,7 @@ import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.reader.RekeyingReader
|
||||
import io.emeraldpay.dshackle.reader.RpcReader
|
||||
import io.emeraldpay.dshackle.reader.TransformingReader
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
@@ -41,7 +42,6 @@ import io.emeraldpay.etherjar.rpc.json.TransactionJson
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
||||
import org.apache.commons.collections4.Factory
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import java.util.function.Function
|
||||
|
||||
/**
|
||||
@@ -174,7 +174,7 @@ open class EthereumReader(
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
// TODO should be always running?
|
||||
return up.isRunning
|
||||
return true // up.isRunning
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
|
||||
@@ -18,11 +18,11 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
@@ -29,7 +30,6 @@ import io.emeraldpay.dshackle.upstream.ethereum.connectors.ConnectorFactory
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnector
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
@@ -80,7 +80,7 @@ open class EthereumRpcUpstream(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return connector.isRunning
|
||||
return connector.isRunning()
|
||||
}
|
||||
|
||||
override fun getApi(): Reader<JsonRpcRequest, JsonRpcResponse> {
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.AuthConfig
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.RpcMetrics
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import io.micrometer.core.instrument.Metrics
|
||||
import io.micrometer.core.instrument.Tag
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcWsClient
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum.connectors
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
interface ConnectorFactory {
|
||||
fun create(upstream: DefaultUpstream, validator: EthereumUpstreamValidator, chain: Chain): EthereumConnector
|
||||
|
||||
@@ -2,9 +2,9 @@ package io.emeraldpay.dshackle.upstream.ethereum.connectors
|
||||
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.springframework.context.Lifecycle
|
||||
|
||||
interface EthereumConnector : Lifecycle {
|
||||
fun getHead(): Head
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum.connectors
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.HttpFactory
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsFactory
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
open class EthereumConnectorFactory(
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.MergedHead
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumRpcHead
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsFactory
|
||||
@@ -14,7 +15,6 @@ import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import java.time.Duration
|
||||
|
||||
class EthereumRpcConnector(
|
||||
@@ -61,7 +61,7 @@ class EthereumRpcConnector(
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
if (head is Lifecycle) {
|
||||
return head.isRunning
|
||||
return head.isRunning()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class EthereumWsConnector(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return head.isRunning
|
||||
return head.isRunning()
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
|
||||
@@ -17,23 +17,17 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.ChainFees
|
||||
import io.emeraldpay.dshackle.upstream.EmptyHead
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.MergedHead
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.PriorityForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import org.springframework.util.ConcurrentReferenceHashMap
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
@@ -80,7 +74,7 @@ open class EthereumPosMultiStream(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return super.isRunning() || reader.isRunning
|
||||
return super.isRunning() || reader.isRunning()
|
||||
}
|
||||
|
||||
override fun getReader(): EthereumReader {
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
@@ -29,9 +31,7 @@ import io.emeraldpay.dshackle.upstream.ethereum.connectors.ConnectorFactory
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnector
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
|
||||
open class EthereumPosRpcUpstream(
|
||||
@@ -80,7 +80,7 @@ open class EthereumPosRpcUpstream(
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
return connector.isRunning
|
||||
return connector.isRunning()
|
||||
}
|
||||
|
||||
override fun getApi(): Reader<JsonRpcRequest, JsonRpcResponse> {
|
||||
|
||||
@@ -17,6 +17,7 @@ package io.emeraldpay.dshackle.upstream.grpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
@@ -24,6 +25,7 @@ import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.Capability
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
@@ -34,10 +36,8 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcGrpcClient
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.reactivestreams.Publisher
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.math.BigInteger
|
||||
|
||||
@@ -18,6 +18,7 @@ package io.emeraldpay.dshackle.upstream.grpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
@@ -26,6 +27,7 @@ import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.Capability
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
@@ -37,10 +39,8 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.reactivestreams.Publisher
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.math.BigInteger
|
||||
|
||||
@@ -18,6 +18,7 @@ package io.emeraldpay.dshackle.upstream.grpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
@@ -26,6 +27,7 @@ import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.Capability
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
@@ -37,10 +39,8 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.rpc.RpcException
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.reactivestreams.Publisher
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.math.BigInteger
|
||||
|
||||
@@ -18,16 +18,16 @@ package io.emeraldpay.dshackle.upstream.grpc
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.upstream.AbstractHead
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.reactivestreams.Publisher
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
@@ -60,7 +60,7 @@ class GrpcHead(
|
||||
* Initiate a new head subscription with connection to the remote
|
||||
*/
|
||||
private fun internalStart(remote: ReactorBlockchainGrpc.ReactorBlockchainStub) {
|
||||
if (this.isRunning) {
|
||||
if (this.isRunning()) {
|
||||
stop()
|
||||
}
|
||||
log.debug("Start Head subscription to ${parent.getId()}")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user