Skip to content

Commit

Permalink
Merge pull request #2278 from planetarium/acs-tx-quota
Browse files Browse the repository at this point in the history
Add `AddTxQuota` and `RemoveTxQuota` to ACS
  • Loading branch information
area363 authored Nov 2, 2023
2 parents 84f891e + 088f8c8 commit f8a14dd
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 48 deletions.
2 changes: 1 addition & 1 deletion Lib9c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace NineChronicles.Headless.AccessControlCenter.AccessControlService
{
public interface IMutableAccessControlService : IAccessControlService
{
void DenyAccess(Address address);
void AllowAccess(Address address);
List<Address> ListBlockedAddresses(int offset, int limit);
void AddTxQuota(Address address, int quota);
void RemoveTxQuota(Address address);
List<Address> ListTxQuotaAddresses(int offset, int limit);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Libplanet.Crypto;
Expand All @@ -16,29 +15,28 @@ public MutableRedisAccessControlService(string storageUri)
{
}

public void DenyAccess(Address address)
public void AddTxQuota(Address address, int quota)
{
_db.StringSet(address.ToString(), "denied");
_db.StringSet(address.ToString(), quota.ToString());
}

public void AllowAccess(Address address)
public void RemoveTxQuota(Address address)
{
_db.KeyDelete(address.ToString());
}

public List<Address> ListBlockedAddresses(int offset, int limit)
public List<Address> ListTxQuotaAddresses(int offset, int limit)
{
var server = _db.Multiplexer.GetServer(_db.Multiplexer.GetEndPoints().First());

var result = (RedisResult[]?)
server.Execute("SCAN", offset.ToString(), "COUNT", limit.ToString());
if (result != null)
{
long newCursor = long.Parse((string)result[0]!);
RedisKey[] keys = (RedisKey[])result[1]!;

return keys.Select(k => new Address(k.ToString())).ToList();
}

return new List<Address>();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,56 @@ namespace NineChronicles.Headless.AccessControlCenter.AccessControlService
{
public class MutableSqliteAccessControlService : SQLiteAccessControlService, IMutableAccessControlService
{
private const string DenyAccessSql =
"INSERT OR IGNORE INTO blocklist (address) VALUES (@Address)";
private const string AllowAccessSql = "DELETE FROM blocklist WHERE address=@Address";
private const string AddTxQuotaSql =
"INSERT OR IGNORE INTO txquotalist (address, quota) VALUES (@Address, @Quota)";
private const string RemoveTxQuotaSql = "DELETE FROM txquotalist WHERE address=@Address";

public MutableSqliteAccessControlService(string connectionString) : base(connectionString)
{
}

public void DenyAccess(Address address)
public void AddTxQuota(Address address, int quota)
{
using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = DenyAccessSql;
command.CommandText = AddTxQuotaSql;
command.Parameters.AddWithValue("@Address", address.ToString());
command.Parameters.AddWithValue("@Quota", quota);
command.ExecuteNonQuery();
}

public void AllowAccess(Address address)
public void RemoveTxQuota(Address address)
{
using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = AllowAccessSql;
command.CommandText = RemoveTxQuotaSql;
command.Parameters.AddWithValue("@Address", address.ToString());
command.ExecuteNonQuery();
}

public List<Address> ListBlockedAddresses(int offset, int limit)
public List<Address> ListTxQuotaAddresses(int offset, int limit)
{
var blockedAddresses = new List<Address>();
var txQuotaAddresses = new List<Address>();

using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = $"SELECT address FROM blocklist LIMIT @Limit OFFSET @Offset";
command.CommandText = $"SELECT address FROM txquotalist LIMIT @Limit OFFSET @Offset";
command.Parameters.AddWithValue("@Limit", limit);
command.Parameters.AddWithValue("@Offset", offset);

using var reader = command.ExecuteReader();
while (reader.Read())
{
blockedAddresses.Add(new Address(reader.GetString(0)));
txQuotaAddresses.Add(new Address(reader.GetString(0)));
}

return blockedAddresses;
return txQuotaAddresses;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using NineChronicles.Headless.AccessControlCenter.AccessControlService;
Expand All @@ -17,22 +18,28 @@ public AccessControlServiceController(IMutableAccessControlService accessControl
}

[HttpGet("entries/{address}")]
public ActionResult<bool> IsAccessDenied(string address)
public ActionResult<int?> GetTxQuota(string address)
{
return _accessControlService.IsAccessDenied(new Address(address));
return _accessControlService.GetTxQuota(new Address(address));
}

[HttpPost("entries/{address}/deny")]
public ActionResult DenyAccess(string address)
[HttpPost("entries/add-tx-quota/{address}/{quota:int}")]
public ActionResult AddTxQuota(string address, int quota)
{
_accessControlService.DenyAccess(new Address(address));
var maxQuota = 10;
if (quota > maxQuota)
{
return BadRequest($"The quota cannot exceed {maxQuota}.");
}

_accessControlService.AddTxQuota(new Address(address), quota);
return Ok();
}

[HttpPost("entries/{address}/allow")]
public ActionResult AllowAccess(string address)
[HttpPost("entries/remove-tx-quota/{address}")]
public ActionResult RemoveTxQuota(string address)
{
_accessControlService.AllowAccess(new Address(address));
_accessControlService.RemoveTxQuota(new Address(address));
return Ok();
}

Expand All @@ -54,7 +61,7 @@ public ActionResult<List<string>> ListBlockedAddresses(int offset, int limit)
}

return _accessControlService
.ListBlockedAddresses(offset, limit)
.ListTxQuotaAddresses(offset, limit)
.Select(a => a.ToString())
.ToList();
}
Expand Down
12 changes: 7 additions & 5 deletions NineChronicles.Headless/Services/RedisAccessControlService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using StackExchange.Redis;
using Libplanet.Crypto;
using Nekoyume.Blockchain;
Expand All @@ -15,16 +16,17 @@ public RedisAccessControlService(string storageUri)
_db = redis.GetDatabase();
}

public bool IsAccessDenied(Address address)
public int? GetTxQuota(Address address)
{
var result = _db.KeyExists(address.ToString());
if (result)
RedisValue result = _db.StringGet(address.ToString());
if (!result.IsNull)
{
Log.ForContext("Source", nameof(IAccessControlService))
.Debug("\"{Address}\" is access denied", address);
.Debug("\"{Address}\" Tx Quota: {Quota}", address, result);
return Convert.ToInt32(result);
}

return result;
return null;
}
}
}
20 changes: 9 additions & 11 deletions NineChronicles.Headless/Services/SQLiteAccessControlService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using Microsoft.Data.Sqlite;
using Libplanet.Crypto;
using Nekoyume.Blockchain;
Expand All @@ -8,9 +9,9 @@ namespace NineChronicles.Headless.Services
public class SQLiteAccessControlService : IAccessControlService
{
private const string CreateTableSql =
"CREATE TABLE IF NOT EXISTS blocklist (address VARCHAR(42))";
private const string CheckAccessSql =
"SELECT EXISTS(SELECT 1 FROM blocklist WHERE address=@Address)";
"CREATE TABLE IF NOT EXISTS txquotalist (address VARCHAR(42), quota INT)";
private const string GetTxQuotaSql =
"SELECT quota FROM txquotalist WHERE address=@Address";

protected readonly string _connectionString;

Expand All @@ -25,26 +26,23 @@ public SQLiteAccessControlService(string connectionString)
command.ExecuteNonQuery();
}

public bool IsAccessDenied(Address address)
public int? GetTxQuota(Address address)
{
using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = CheckAccessSql;
command.CommandText = GetTxQuotaSql;
command.Parameters.AddWithValue("@Address", address.ToString());

var queryResult = command.ExecuteScalar();

var result = queryResult is not null && (long)queryResult == 1;

if (result)
if (queryResult != null)
{
Log.ForContext("Source", nameof(IAccessControlService))
.Debug("\"{Address}\" is access denied", address);
return Convert.ToInt32(queryResult);
}

return result;
return null;
}
}
}

0 comments on commit f8a14dd

Please sign in to comment.