Merge pull request #5250 from ghubstan/03-fix-interceptor-method-key-lookup

Fix call rate metering interceptor bug
This commit is contained in:
sqrrm 2021-03-09 11:50:08 +01:00 committed by GitHub
commit 6f0f0ef5fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 149 additions and 125 deletions

View file

@ -53,6 +53,8 @@
} }
@test "test getversion" { @test "test getversion" {
# Wait 1 second before calling getversion again.
sleep 1
load 'version-parser' load 'version-parser'
run ./bisq-cli --password=xyz getversion run ./bisq-cli --password=xyz getversion
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
@ -118,6 +120,8 @@
} }
@test "test setwalletpassword oldpwd newpwd" { @test "test setwalletpassword oldpwd newpwd" {
# Wait 5 seconds before calling setwalletpassword again.
sleep 5
run ./bisq-cli --password=xyz setwalletpassword --wallet-password="a b c" --new-wallet-password="d e f" run ./bisq-cli --password=xyz setwalletpassword --wallet-password="a b c" --new-wallet-password="d e f"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "actual output: $output" >&2 echo "actual output: $output" >&2
@ -137,7 +141,7 @@
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "actual output: $output" >&2 echo "actual output: $output" >&2
[ "$output" = "wallet decrypted" ] [ "$output" = "wallet decrypted" ]
sleep 1 sleep 3
} }
@test "test getbalance when wallet available & unlocked with 0 btc balance" { @test "test getbalance when wallet available & unlocked with 0 btc balance" {
@ -151,7 +155,7 @@
} }
@test "test getunusedbsqaddress" { @test "test getunusedbsqaddress" {
run ./bisq-cli --password=xyz getfundingaddresses run ./bisq-cli --password=xyz getunusedbsqaddress
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
} }
@ -163,6 +167,8 @@
} }
@test "test getaddressbalance bogus address argument" { @test "test getaddressbalance bogus address argument" {
# Wait 1 second before calling getaddressbalance again.
sleep 1
run ./bisq-cli --password=xyz getaddressbalance --address=bogus run ./bisq-cli --password=xyz getaddressbalance --address=bogus
[ "$status" -eq 1 ] [ "$status" -eq 1 ]
echo "actual output: $output" >&2 echo "actual output: $output" >&2
@ -187,16 +193,22 @@
} }
@test "test getoffers sell eur check return status" { @test "test getoffers sell eur check return status" {
# Wait 1 second before calling getoffers again.
sleep 1
run ./bisq-cli --password=xyz getoffers --direction=sell --currency-code=eur run ./bisq-cli --password=xyz getoffers --direction=sell --currency-code=eur
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
} }
@test "test getoffers buy eur check return status" { @test "test getoffers buy eur check return status" {
# Wait 1 second before calling getoffers again.
sleep 1
run ./bisq-cli --password=xyz getoffers --direction=buy --currency-code=eur run ./bisq-cli --password=xyz getoffers --direction=buy --currency-code=eur
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
} }
@test "test getoffers sell gbp check return status" { @test "test getoffers sell gbp check return status" {
# Wait 1 second before calling getoffers again.
sleep 1
run ./bisq-cli --password=xyz getoffers --direction=sell --currency-code=gbp run ./bisq-cli --password=xyz getoffers --direction=sell --currency-code=gbp
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
} }
@ -216,3 +228,9 @@
[ "${lines[1]}" = "Usage: bisq-cli [options] <method> [params]" ] [ "${lines[1]}" = "Usage: bisq-cli [options] <method> [params]" ]
# TODO add asserts after help text is modified for new endpoints # TODO add asserts after help text is modified for new endpoints
} }
@test "test takeoffer method --help" {
run ./bisq-cli --password=xyz takeoffer --help
[ "$status" -eq 0 ]
[ "${lines[0]}" = "takeoffer" ]
}

View file

@ -17,11 +17,14 @@
package bisq.apitest; package bisq.apitest;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInfo;
@ -29,15 +32,20 @@ import org.junit.jupiter.api.TestInfo;
import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.apitest.config.BisqAppConfig.arbdaemon; import static bisq.apitest.config.BisqAppConfig.arbdaemon;
import static bisq.apitest.config.BisqAppConfig.bobdaemon; import static bisq.apitest.config.BisqAppConfig.bobdaemon;
import static bisq.proto.grpc.DisputeAgentsGrpc.getRegisterDisputeAgentMethod;
import static bisq.proto.grpc.GetVersionGrpc.getGetVersionMethod;
import static java.net.InetAddress.getLoopbackAddress; import static java.net.InetAddress.getLoopbackAddress;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import bisq.apitest.config.ApiTestConfig; import bisq.apitest.config.ApiTestConfig;
import bisq.apitest.method.BitcoinCliHelper; import bisq.apitest.method.BitcoinCliHelper;
import bisq.cli.GrpcClient; import bisq.cli.GrpcClient;
import bisq.daemon.grpc.GrpcVersionService;
import bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig;
/** /**
* Base class for all test types: 'method', 'scenario' and 'e2e'. * Base class for all test types: 'method', 'scenario' and 'e2e'.
@ -64,6 +72,7 @@ import bisq.cli.GrpcClient;
* <p> * <p>
* Initial Bob balances & accounts: 10.0 BTC, 1500000.00 BSQ, USD PerfectMoney dummy * Initial Bob balances & accounts: 10.0 BTC, 1500000.00 BSQ, USD PerfectMoney dummy
*/ */
@Slf4j
public class ApiTestCase { public class ApiTestCase {
protected static Scaffold scaffold; protected static Scaffold scaffold;
@ -79,12 +88,12 @@ public class ApiTestCase {
public static void setUpScaffold(Enum<?>... supportingApps) public static void setUpScaffold(Enum<?>... supportingApps)
throws InterruptedException, ExecutionException, IOException { throws InterruptedException, ExecutionException, IOException {
scaffold = new Scaffold(stream(supportingApps).map(Enum::name) String[] params = new String[]{
.collect(Collectors.joining(","))) "--supportingApps", stream(supportingApps).map(Enum::name).collect(Collectors.joining(",")),
.setUp(); "--callRateMeteringConfigPath", defaultRateMeterInterceptorConfig().getAbsolutePath(),
config = scaffold.config; "--enableBisqDebugging", "false"
bitcoinCli = new BitcoinCliHelper((config)); };
createGrpcClients(); setUpScaffold(params);
} }
public static void setUpScaffold(String[] params) public static void setUpScaffold(String[] params)
@ -139,4 +148,37 @@ public class ApiTestCase {
? testInfo.getTestMethod().get().getName() ? testInfo.getTestMethod().get().getName()
: "unknown test name"; : "unknown test name";
} }
protected static File defaultRateMeterInterceptorConfig() {
GrpcServiceRateMeteringConfig.Builder builder = new GrpcServiceRateMeteringConfig.Builder();
builder.addCallRateMeter(GrpcVersionService.class.getSimpleName(),
getGetVersionMethod().getFullMethodName(),
1,
SECONDS);
// Only GrpcVersionService is @VisibleForTesting, so we need to
// hardcode other grpcServiceClassName parameter values used in
// builder.addCallRateMeter(...).
builder.addCallRateMeter("GrpcDisputeAgentsService",
getRegisterDisputeAgentMethod().getFullMethodName(),
10, // Same as default.
SECONDS);
// Define rate meters for non-existent method 'disabled', to override other grpc
// services' default rate meters -- defined in their rateMeteringInterceptor()
// methods.
String[] serviceClassNames = new String[]{
"GrpcGetTradeStatisticsService",
"GrpcHelpService",
"GrpcOffersService",
"GrpcPaymentAccountsService",
"GrpcPriceService",
"GrpcTradesService",
"GrpcWalletsService"
};
for (String service : serviceClassNames) {
builder.addCallRateMeter(service, "disabled", 1, MILLISECONDS);
}
File file = builder.build();
file.deleteOnExit();
return file;
}
} }

View file

@ -19,9 +19,6 @@ package bisq.apitest.method;
import io.grpc.StatusRuntimeException; import io.grpc.StatusRuntimeException;
import java.io.File;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
@ -35,19 +32,9 @@ import org.junit.jupiter.api.TestMethodOrder;
import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind; import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind;
import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.common.file.FileUtil.deleteFileIfExists;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import bisq.daemon.grpc.GrpcVersionService;
import bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig;
@Disabled @Disabled
@Slf4j @Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -55,13 +42,9 @@ public class CallRateMeteringInterceptorTest extends MethodTest {
private static final GetVersionTest getVersionTest = new GetVersionTest(); private static final GetVersionTest getVersionTest = new GetVersionTest();
private static File callRateMeteringConfigFile;
@BeforeAll @BeforeAll
public static void setUp() { public static void setUp() {
callRateMeteringConfigFile = buildInterceptorConfigFile(); startSupportingApps(false,
startSupportingApps(callRateMeteringConfigFile,
false,
false, false,
bitcoind, alicedaemon); bitcoind, alicedaemon);
} }
@ -102,37 +85,6 @@ public class CallRateMeteringInterceptorTest extends MethodTest {
@AfterAll @AfterAll
public static void tearDown() { public static void tearDown() {
try {
deleteFileIfExists(callRateMeteringConfigFile);
} catch (IOException ex) {
log.error(ex.getMessage());
}
tearDownScaffold(); tearDownScaffold();
} }
public static File buildInterceptorConfigFile() {
GrpcServiceRateMeteringConfig.Builder builder = new GrpcServiceRateMeteringConfig.Builder();
builder.addCallRateMeter(GrpcVersionService.class.getSimpleName(),
"getVersion",
1,
SECONDS);
builder.addCallRateMeter(GrpcVersionService.class.getSimpleName(),
"shouldNotBreakAnything",
1000,
DAYS);
// Only GrpcVersionService is @VisibleForTesting, so we hardcode the class names.
builder.addCallRateMeter("GrpcOffersService",
"createOffer",
5,
MINUTES);
builder.addCallRateMeter("GrpcTradesService",
"takeOffer",
10,
DAYS);
builder.addCallRateMeter("GrpcTradesService",
"withdrawFunds",
3,
HOURS);
return builder.build();
}
} }

View file

@ -71,8 +71,11 @@ public class MethodTest extends ApiTestCase {
boolean generateBtcBlock, boolean generateBtcBlock,
Enum<?>... supportingApps) { Enum<?>... supportingApps) {
try { try {
// Disable call rate metering where there is no callRateMeteringConfigFile.
File callRateMeteringConfigFile = defaultRateMeterInterceptorConfig();
setUpScaffold(new String[]{ setUpScaffold(new String[]{
"--supportingApps", toNameList.apply(supportingApps), "--supportingApps", toNameList.apply(supportingApps),
"--callRateMeteringConfigPath", callRateMeteringConfigFile.getAbsolutePath(),
"--enableBisqDebugging", "false" "--enableBisqDebugging", "false"
}); });
doPostStartup(registerDisputeAgents, generateBtcBlock); doPostStartup(registerDisputeAgents, generateBtcBlock);

View file

@ -33,7 +33,6 @@ import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind;
import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.apitest.config.BisqAppConfig.arbdaemon; import static bisq.apitest.config.BisqAppConfig.arbdaemon;
import static bisq.apitest.config.BisqAppConfig.seednode; import static bisq.apitest.config.BisqAppConfig.seednode;
import static bisq.apitest.method.CallRateMeteringInterceptorTest.buildInterceptorConfigFile;
import static bisq.common.file.FileUtil.deleteFileIfExists; import static bisq.common.file.FileUtil.deleteFileIfExists;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -55,7 +54,7 @@ public class StartupTest extends MethodTest {
@BeforeAll @BeforeAll
public static void setUp() { public static void setUp() {
try { try {
callRateMeteringConfigFile = buildInterceptorConfigFile(); callRateMeteringConfigFile = defaultRateMeterInterceptorConfig();
startSupportingApps(callRateMeteringConfigFile, startSupportingApps(callRateMeteringConfigFile,
false, false,
false, false,

View file

@ -2,7 +2,6 @@ package bisq.daemon.grpc;
import bisq.core.api.CoreApi; import bisq.core.api.CoreApi;
import bisq.proto.grpc.DisputeAgentsGrpc;
import bisq.proto.grpc.RegisterDisputeAgentReply; import bisq.proto.grpc.RegisterDisputeAgentReply;
import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.RegisterDisputeAgentRequest;
@ -17,6 +16,8 @@ import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.DisputeAgentsGrpc.DisputeAgentsImplBase;
import static bisq.proto.grpc.DisputeAgentsGrpc.getRegisterDisputeAgentMethod;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -25,7 +26,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcDisputeAgentsService extends DisputeAgentsGrpc.DisputeAgentsImplBase { class GrpcDisputeAgentsService extends DisputeAgentsImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -59,9 +60,9 @@ class GrpcDisputeAgentsService extends DisputeAgentsGrpc.DisputeAgentsImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
// You can only register mainnet dispute agents in the UI. // Do not limit devs' ability to test agent registration
// Do not limit devs' ability to register test agents. // and call validation in regtest arbitration daemons.
put("registerDisputeAgent", new GrpcCallRateMeter(1, SECONDS)); put(getRegisterDisputeAgentMethod().getFullMethodName(), new GrpcCallRateMeter(10, SECONDS));
}} }}
))); )));
} }

View file

@ -3,7 +3,6 @@ package bisq.daemon.grpc;
import bisq.core.api.CoreApi; import bisq.core.api.CoreApi;
import bisq.core.trade.statistics.TradeStatistics3; import bisq.core.trade.statistics.TradeStatistics3;
import bisq.proto.grpc.GetTradeStatisticsGrpc;
import bisq.proto.grpc.GetTradeStatisticsReply; import bisq.proto.grpc.GetTradeStatisticsReply;
import bisq.proto.grpc.GetTradeStatisticsRequest; import bisq.proto.grpc.GetTradeStatisticsRequest;
@ -19,6 +18,8 @@ import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.GetTradeStatisticsGrpc.GetTradeStatisticsImplBase;
import static bisq.proto.grpc.GetTradeStatisticsGrpc.getGetTradeStatisticsMethod;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -27,7 +28,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcGetTradeStatisticsService extends GetTradeStatisticsGrpc.GetTradeStatisticsImplBase { class GrpcGetTradeStatisticsService extends GetTradeStatisticsImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -64,7 +65,7 @@ class GrpcGetTradeStatisticsService extends GetTradeStatisticsGrpc.GetTradeStati
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getTradeStatistics", new GrpcCallRateMeter(1, SECONDS)); put(getGetTradeStatisticsMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
}} }}
))); )));
} }

View file

@ -21,7 +21,6 @@ import bisq.core.api.CoreApi;
import bisq.proto.grpc.GetMethodHelpReply; import bisq.proto.grpc.GetMethodHelpReply;
import bisq.proto.grpc.GetMethodHelpRequest; import bisq.proto.grpc.GetMethodHelpRequest;
import bisq.proto.grpc.HelpGrpc;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
@ -34,6 +33,8 @@ import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.HelpGrpc.HelpImplBase;
import static bisq.proto.grpc.HelpGrpc.getGetMethodHelpMethod;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -42,7 +43,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcHelpService extends HelpGrpc.HelpImplBase { class GrpcHelpService extends HelpImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -76,7 +77,7 @@ class GrpcHelpService extends HelpGrpc.HelpImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getMethodHelp", new GrpcCallRateMeter(1, SECONDS)); put(getGetMethodHelpMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
}} }}
))); )));
} }

View file

@ -34,7 +34,6 @@ import bisq.proto.grpc.GetOfferReply;
import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOfferRequest;
import bisq.proto.grpc.GetOffersReply; import bisq.proto.grpc.GetOffersReply;
import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.GetOffersRequest;
import bisq.proto.grpc.OffersGrpc;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
@ -50,6 +49,7 @@ import lombok.extern.slf4j.Slf4j;
import static bisq.core.api.model.OfferInfo.toOfferInfo; import static bisq.core.api.model.OfferInfo.toOfferInfo;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.OffersGrpc.*;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -59,7 +59,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcOffersService extends OffersGrpc.OffersImplBase { class GrpcOffersService extends OffersImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -193,12 +193,12 @@ class GrpcOffersService extends OffersGrpc.OffersImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getOffer", new GrpcCallRateMeter(1, SECONDS)); put(getGetOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getMyOffer", new GrpcCallRateMeter(1, SECONDS)); put(getGetMyOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getOffers", new GrpcCallRateMeter(1, SECONDS)); put(getGetOffersMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getMyOffers", new GrpcCallRateMeter(1, SECONDS)); put(getGetMyOffersMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("createOffer", new GrpcCallRateMeter(1, MINUTES)); put(getCreateOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("cancelOffer", new GrpcCallRateMeter(1, MINUTES)); put(getCancelOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
}} }}
))); )));
} }

View file

@ -29,7 +29,6 @@ import bisq.proto.grpc.GetPaymentAccountsReply;
import bisq.proto.grpc.GetPaymentAccountsRequest; import bisq.proto.grpc.GetPaymentAccountsRequest;
import bisq.proto.grpc.GetPaymentMethodsReply; import bisq.proto.grpc.GetPaymentMethodsReply;
import bisq.proto.grpc.GetPaymentMethodsRequest; import bisq.proto.grpc.GetPaymentMethodsRequest;
import bisq.proto.grpc.PaymentAccountsGrpc;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
@ -43,6 +42,7 @@ import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.PaymentAccountsGrpc.*;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -52,7 +52,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcPaymentAccountsService extends PaymentAccountsGrpc.PaymentAccountsImplBase { class GrpcPaymentAccountsService extends PaymentAccountsImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -135,10 +135,10 @@ class GrpcPaymentAccountsService extends PaymentAccountsGrpc.PaymentAccountsImpl
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("createPaymentAccount", new GrpcCallRateMeter(1, MINUTES)); put(getCreatePaymentAccountMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("getPaymentAccounts", new GrpcCallRateMeter(1, SECONDS)); put(getGetPaymentAccountsMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getPaymentMethods", new GrpcCallRateMeter(1, SECONDS)); put(getGetPaymentMethodsMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getPaymentAccountForm", new GrpcCallRateMeter(1, SECONDS)); put(getGetPaymentAccountFormMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
}} }}
))); )));
} }

View file

@ -21,7 +21,6 @@ import bisq.core.api.CoreApi;
import bisq.proto.grpc.MarketPriceReply; import bisq.proto.grpc.MarketPriceReply;
import bisq.proto.grpc.MarketPriceRequest; import bisq.proto.grpc.MarketPriceRequest;
import bisq.proto.grpc.PriceGrpc;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
@ -34,6 +33,8 @@ import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.PriceGrpc.PriceImplBase;
import static bisq.proto.grpc.PriceGrpc.getGetMarketPriceMethod;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -42,7 +43,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcPriceService extends PriceGrpc.PriceImplBase { class GrpcPriceService extends PriceImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -78,7 +79,7 @@ class GrpcPriceService extends PriceGrpc.PriceImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getMarketPrice", new GrpcCallRateMeter(1, SECONDS)); put(getGetMarketPriceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
}} }}
))); )));
} }

View file

@ -31,7 +31,6 @@ import bisq.proto.grpc.KeepFundsReply;
import bisq.proto.grpc.KeepFundsRequest; import bisq.proto.grpc.KeepFundsRequest;
import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.TradesGrpc;
import bisq.proto.grpc.WithdrawFundsReply; import bisq.proto.grpc.WithdrawFundsReply;
import bisq.proto.grpc.WithdrawFundsRequest; import bisq.proto.grpc.WithdrawFundsRequest;
@ -47,6 +46,7 @@ import lombok.extern.slf4j.Slf4j;
import static bisq.core.api.model.TradeInfo.toTradeInfo; import static bisq.core.api.model.TradeInfo.toTradeInfo;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.TradesGrpc.*;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -56,7 +56,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcTradesService extends TradesGrpc.TradesImplBase { class GrpcTradesService extends TradesImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -169,12 +169,12 @@ class GrpcTradesService extends TradesGrpc.TradesImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getTrade", new GrpcCallRateMeter(1, SECONDS)); put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("takeOffer", new GrpcCallRateMeter(1, MINUTES)); put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("confirmPaymentStarted", new GrpcCallRateMeter(1, MINUTES)); put(getConfirmPaymentStartedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("confirmPaymentReceived", new GrpcCallRateMeter(1, MINUTES)); put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("keepFunds", new GrpcCallRateMeter(1, MINUTES)); put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("withdrawFunds", new GrpcCallRateMeter(1, MINUTES)); put(getWithdrawFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
}} }}
))); )));
} }

View file

@ -19,7 +19,6 @@ package bisq.daemon.grpc;
import bisq.core.api.CoreApi; import bisq.core.api.CoreApi;
import bisq.proto.grpc.GetVersionGrpc;
import bisq.proto.grpc.GetVersionReply; import bisq.proto.grpc.GetVersionReply;
import bisq.proto.grpc.GetVersionRequest; import bisq.proto.grpc.GetVersionRequest;
@ -36,6 +35,8 @@ import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.GetVersionGrpc.GetVersionImplBase;
import static bisq.proto.grpc.GetVersionGrpc.getGetVersionMethod;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -45,7 +46,7 @@ import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@VisibleForTesting @VisibleForTesting
@Slf4j @Slf4j
public class GrpcVersionService extends GetVersionGrpc.GetVersionImplBase { public class GrpcVersionService extends GetVersionImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -77,7 +78,7 @@ public class GrpcVersionService extends GetVersionGrpc.GetVersionImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getVersion", new GrpcCallRateMeter(1, SECONDS)); put(getGetVersionMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
}} }}
))); )));
} }

View file

@ -51,7 +51,6 @@ import bisq.proto.grpc.UnlockWalletReply;
import bisq.proto.grpc.UnlockWalletRequest; import bisq.proto.grpc.UnlockWalletRequest;
import bisq.proto.grpc.UnsetTxFeeRatePreferenceReply; import bisq.proto.grpc.UnsetTxFeeRatePreferenceReply;
import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest; import bisq.proto.grpc.UnsetTxFeeRatePreferenceRequest;
import bisq.proto.grpc.WalletsGrpc;
import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
@ -73,6 +72,7 @@ import org.jetbrains.annotations.NotNull;
import static bisq.core.api.model.TxInfo.toTxInfo; import static bisq.core.api.model.TxInfo.toTxInfo;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
import static bisq.proto.grpc.WalletsGrpc.*;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -82,7 +82,7 @@ import bisq.daemon.grpc.interceptor.CallRateMeteringInterceptor;
import bisq.daemon.grpc.interceptor.GrpcCallRateMeter; import bisq.daemon.grpc.interceptor.GrpcCallRateMeter;
@Slf4j @Slf4j
class GrpcWalletsService extends WalletsGrpc.WalletsImplBase { class GrpcWalletsService extends WalletsImplBase {
private final CoreApi coreApi; private final CoreApi coreApi;
private final GrpcExceptionHandler exceptionHandler; private final GrpcExceptionHandler exceptionHandler;
@ -352,24 +352,24 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass()) return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{ new HashMap<>() {{
put("getBalances", new GrpcCallRateMeter(1, SECONDS)); put(getGetBalancesMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getAddressBalance", new GrpcCallRateMeter(1, SECONDS)); put(getGetAddressBalanceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getFundingAddresses", new GrpcCallRateMeter(1, SECONDS)); put(getGetFundingAddressesMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getUnusedBsqAddress", new GrpcCallRateMeter(1, SECONDS)); put(getGetUnusedBsqAddressMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("sendBsq", new GrpcCallRateMeter(1, MINUTES)); put(getSendBsqMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("sendBtc", new GrpcCallRateMeter(1, MINUTES)); put(getSendBtcMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put("getTxFeeRate", new GrpcCallRateMeter(1, SECONDS)); put(getGetTxFeeRateMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("setTxFeeRatePreference", new GrpcCallRateMeter(1, SECONDS)); put(getSetTxFeeRatePreferenceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("unsetTxFeeRatePreference", new GrpcCallRateMeter(1, SECONDS)); put(getUnsetTxFeeRatePreferenceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("getTransaction", new GrpcCallRateMeter(1, SECONDS)); put(getGetTransactionMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
// Trying to set or remove a wallet password several times before the 1st attempt has time to // Trying to set or remove a wallet password several times before the 1st attempt has time to
// persist the change to disk may corrupt the wallet, so allow only 1 attempt per 5 seconds. // persist the change to disk may corrupt the wallet, so allow only 1 attempt per 5 seconds.
put("setWalletPassword", new GrpcCallRateMeter(1, SECONDS, 5)); put(getSetWalletPasswordMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS, 5));
put("removeWalletPassword", new GrpcCallRateMeter(1, SECONDS, 5)); put(getRemoveWalletPasswordMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS, 5));
put("lockWallet", new GrpcCallRateMeter(1, SECONDS)); put(getLockWalletMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put("unlockWallet", new GrpcCallRateMeter(1, SECONDS)); put(getUnlockWalletMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
}} }}
))); )));
} }

View file

@ -27,7 +27,6 @@ import org.apache.commons.lang3.StringUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -85,16 +84,19 @@ public final class CallRateMeteringInterceptor implements ServerInterceptor {
ServerCall<?, ?> serverCall) ServerCall<?, ?> serverCall)
throws StatusRuntimeException { throws StatusRuntimeException {
String msg = getDefaultRateExceededError(methodName, rateMeter); String msg = getDefaultRateExceededError(methodName, rateMeter);
log.warn(StringUtils.capitalize(msg) + "."); log.warn(msg + ".");
serverCall.close(PERMISSION_DENIED.withDescription(msg), new Metadata()); serverCall.close(PERMISSION_DENIED.withDescription(msg.toLowerCase()), new Metadata());
} }
private String getDefaultRateExceededError(String methodName, private String getDefaultRateExceededError(String methodName,
GrpcCallRateMeter rateMeter) { GrpcCallRateMeter rateMeter) {
// The derived method name may not be an exact match to CLI's method name. // The derived method name may not be an exact match to CLI's method name.
String timeUnitName = StringUtils.chop(rateMeter.getTimeUnit().name().toLowerCase()); String timeUnitName = StringUtils.chop(rateMeter.getTimeUnit().name().toLowerCase());
return format("the maximum allowed number of %s calls (%d/%s) has been exceeded", // Just print 'getversion', not the grpc method descriptor's
methodName.toLowerCase(), // full-method-name: 'io.bisq.protobuffer.getversion/getversion'.
String loggedMethodName = methodName.split("/")[1];
return format("The maximum allowed number of %s calls (%d/%s) has been exceeded",
loggedMethodName,
rateMeter.getAllowedCallsPerTimeWindow(), rateMeter.getAllowedCallsPerTimeWindow(),
timeUnitName); timeUnitName);
} }
@ -106,11 +108,11 @@ public final class CallRateMeteringInterceptor implements ServerInterceptor {
} }
private String getRateMeterKey(ServerCall<?, ?> serverCall) { private String getRateMeterKey(ServerCall<?, ?> serverCall) {
// Get the rate meter map key from the full rpc service name. The key name // Get the rate meter map key from the server call method descriptor. The
// is hard coded in the Grpc*Service interceptors() method. // returned String (e.g., 'io.bisq.protobuffer.Offers/CreateOffer') will match
String fullServiceName = serverCall.getMethodDescriptor().getServiceName(); // a map entry key in the 'serviceCallRateMeters' constructor argument, if it
return StringUtils.uncapitalize(Objects.requireNonNull(fullServiceName) // was defined in the Grpc*Service class' rateMeteringInterceptor method.
.substring("io.bisq.protobuffer.".length())); return serverCall.getMethodDescriptor().getFullMethodName();
} }
@Override @Override

View file

@ -55,8 +55,11 @@ public class GrpcCallRateMeter {
public String getCallsCountProgress(String calledMethodName) { public String getCallsCountProgress(String calledMethodName) {
String shortTimeUnitName = StringUtils.chop(timeUnit.name().toLowerCase()); String shortTimeUnitName = StringUtils.chop(timeUnit.name().toLowerCase());
// Just print 'GetVersion has been called N times...',
// not 'io.bisq.protobuffer.GetVersion/GetVersion has been called N times...'
String loggedMethodName = calledMethodName.split("/")[1];
return format("%s has been called %d time%s in the last %s, rate limit is %d/%s", return format("%s has been called %d time%s in the last %s, rate limit is %d/%s",
calledMethodName, loggedMethodName,
callTimestamps.size(), callTimestamps.size(),
callTimestamps.size() == 1 ? "" : "s", callTimestamps.size() == 1 ? "" : "s",
shortTimeUnitName, shortTimeUnitName,