mirror of
https://github.com/grassrootseconomics/cic-custodial.git
synced 2024-11-23 06:36:46 +01:00
fix (braking change): gas refill params (#89)
NOTE: This needs the db to be nuked if you are running a test cluster * updated gas refilling logic to reflect EthFaucet contract * fully dependant on on-chain contract to refill and unlock gas * minor fixes to nonce bootstrapper Ideal Values: INITIAL GIFT = 0.015 THRESHOLD = 0.01 TIME = 12 * 60 * 60 # Sample for 30 txs EXTREME LOW = 0.00675 LOW GAS USAGE = 0.00694605 RISING = 0.0135 HIGH = 0.027
This commit is contained in:
parent
8ef2311d8e
commit
b9d3c219c8
@ -60,6 +60,7 @@ func main() {
|
|||||||
custodial, err := custodial.NewCustodial(custodial.Opts{
|
custodial, err := custodial.NewCustodial(custodial.Opts{
|
||||||
CeloProvider: celoProvider,
|
CeloProvider: celoProvider,
|
||||||
LockProvider: lockProvider,
|
LockProvider: lockProvider,
|
||||||
|
Logg: lo,
|
||||||
Noncestore: redisNoncestore,
|
Noncestore: redisNoncestore,
|
||||||
Store: store,
|
Store: store,
|
||||||
RedisClient: redisPool.Client,
|
RedisClient: redisPool.Client,
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// HandleSignTransfer godoc
|
// HandleSignTransfer godoc
|
||||||
|
//
|
||||||
// @Summary Sign and dispatch transfer request.
|
// @Summary Sign and dispatch transfer request.
|
||||||
// @Description Sign and dispatch a transfer request.
|
// @Description Sign and dispatch a transfer request.
|
||||||
// @Tags network
|
// @Tags network
|
||||||
@ -42,7 +43,7 @@ func HandleSignTransfer(cu *custodial.Custodial) func(echo.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
accountActive, gasQuota, err := cu.Store.GetAccountStatus(c.Request().Context(), req.From)
|
accountActive, gasLock, err := cu.Store.GetAccountStatus(c.Request().Context(), req.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -54,36 +55,15 @@ func HandleSignTransfer(cu *custodial.Custodial) func(echo.Context) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
trackingId := uuid.NewString()
|
if gasLock {
|
||||||
|
|
||||||
if gasQuota < 1 {
|
|
||||||
gasRefillPayload, err := json.Marshal(task.AccountPayload{
|
|
||||||
PublicKey: req.From,
|
|
||||||
TrackingId: trackingId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
|
||||||
c.Request().Context(),
|
|
||||||
tasker.AccountRefillGasTask,
|
|
||||||
tasker.DefaultPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Id: trackingId,
|
|
||||||
Payload: gasRefillPayload,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusForbidden, ErrResp{
|
return c.JSON(http.StatusForbidden, ErrResp{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message: "Out of gas, refill pending. Try again later.",
|
Message: "Gas lock. Gas balance unavailable. Try again later.",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackingId := uuid.NewString()
|
||||||
|
|
||||||
taskPayload, err := json.Marshal(task.TransferPayload{
|
taskPayload, err := json.Marshal(task.TransferPayload{
|
||||||
TrackingId: trackingId,
|
TrackingId: trackingId,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
|
@ -15,12 +15,14 @@ import (
|
|||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
"github.com/grassrootseconomics/w3-celo-patch"
|
||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
|
"github.com/zerodha/logf"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Opts struct {
|
Opts struct {
|
||||||
CeloProvider *celoutils.Provider
|
CeloProvider *celoutils.Provider
|
||||||
LockProvider *redislock.Client
|
LockProvider *redislock.Client
|
||||||
|
Logg logf.Logger
|
||||||
Noncestore nonce.Noncestore
|
Noncestore nonce.Noncestore
|
||||||
Store store.Store
|
Store store.Store
|
||||||
RedisClient *redis.Client
|
RedisClient *redis.Client
|
||||||
@ -54,11 +56,13 @@ func NewCustodial(o Opts) (*Custodial, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = o.Noncestore.Peek(ctx, o.SystemPublicKey)
|
systemNonce, err := o.Noncestore.Peek(ctx, o.SystemPublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o.Logg.Info("custodial: loaded_nonce", "system_nonce", systemNonce)
|
||||||
|
|
||||||
privateKey, err := eth_crypto.HexToECDSA(o.SystemPrivateKey)
|
privateKey, err := eth_crypto.HexToECDSA(o.SystemPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -37,14 +37,18 @@ func NewRedisNoncestore(o Opts) Noncestore {
|
|||||||
|
|
||||||
func (n *RedisNoncestore) Peek(ctx context.Context, publicKey string) (uint64, error) {
|
func (n *RedisNoncestore) Peek(ctx context.Context, publicKey string) (uint64, error) {
|
||||||
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
||||||
|
if err != nil {
|
||||||
if err == redis.Nil {
|
if err == redis.Nil {
|
||||||
nonce, err = n.bootstrap(ctx, publicKey)
|
nonce, err = n.bootstrap(ctx, publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
|
||||||
|
return nonce, nil
|
||||||
|
} else {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nonce, nil
|
return nonce, nil
|
||||||
}
|
}
|
||||||
@ -55,14 +59,16 @@ func (n *RedisNoncestore) Acquire(ctx context.Context, publicKey string) (uint64
|
|||||||
)
|
)
|
||||||
|
|
||||||
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
||||||
|
if err != nil {
|
||||||
if err == redis.Nil {
|
if err == redis.Nil {
|
||||||
nonce, err = n.bootstrap(ctx, publicKey)
|
nonce, err = n.bootstrap(ctx, publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = n.redis.Client.Incr(ctx, publicKey).Err()
|
err = n.redis.Client.Incr(ctx, publicKey).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -22,10 +22,10 @@ func (s *PgStore) ActivateAccount(
|
|||||||
func (s *PgStore) GetAccountStatus(
|
func (s *PgStore) GetAccountStatus(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
publicAddress string,
|
publicAddress string,
|
||||||
) (bool, int, error) {
|
) (bool, bool, error) {
|
||||||
var (
|
var (
|
||||||
accountActive bool
|
accountActive bool
|
||||||
gasQuota int
|
gasLock bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := s.db.QueryRow(
|
if err := s.db.QueryRow(
|
||||||
@ -34,21 +34,21 @@ func (s *PgStore) GetAccountStatus(
|
|||||||
publicAddress,
|
publicAddress,
|
||||||
).Scan(
|
).Scan(
|
||||||
&accountActive,
|
&accountActive,
|
||||||
&gasQuota,
|
&gasLock,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return false, 0, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return accountActive, gasQuota, nil
|
return accountActive, gasLock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PgStore) DecrGasQuota(
|
func (s *PgStore) GasLock(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
publicAddress string,
|
publicAddress string,
|
||||||
) error {
|
) error {
|
||||||
if _, err := s.db.Exec(
|
if _, err := s.db.Exec(
|
||||||
ctx,
|
ctx,
|
||||||
s.queries.DecrGasQuota,
|
s.queries.GasLock,
|
||||||
publicAddress,
|
publicAddress,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -57,13 +57,13 @@ func (s *PgStore) DecrGasQuota(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PgStore) ResetGasQuota(
|
func (s *PgStore) GasUnlock(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
publicAddress string,
|
publicAddress string,
|
||||||
) error {
|
) error {
|
||||||
if _, err := s.db.Exec(
|
if _, err := s.db.Exec(
|
||||||
ctx,
|
ctx,
|
||||||
s.queries.ResetGasQuota,
|
s.queries.GasUnlock,
|
||||||
publicAddress,
|
publicAddress,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -27,10 +27,10 @@ type (
|
|||||||
UpdateDispatchStatus(context.Context, bool, string, uint64) error
|
UpdateDispatchStatus(context.Context, bool, string, uint64) error
|
||||||
// Account related actions.
|
// Account related actions.
|
||||||
ActivateAccount(context.Context, string) error
|
ActivateAccount(context.Context, string) error
|
||||||
GetAccountStatus(context.Context, string) (bool, int, error)
|
GetAccountStatus(context.Context, string) (bool, bool, error)
|
||||||
// Gas quota related actions.
|
// Gas quota related actions.
|
||||||
DecrGasQuota(context.Context, string) error
|
GasLock(context.Context, string) error
|
||||||
ResetGasQuota(context.Context, string) error
|
GasUnlock(context.Context, string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
Opts struct {
|
Opts struct {
|
||||||
@ -57,8 +57,8 @@ type (
|
|||||||
// Account related queries.
|
// Account related queries.
|
||||||
ActivateAccount string `query:"activate-account"`
|
ActivateAccount string `query:"activate-account"`
|
||||||
GetAccountStatus string `query:"get-account-status-by-address"`
|
GetAccountStatus string `query:"get-account-status-by-address"`
|
||||||
DecrGasQuota string `query:"decr-gas-quota"`
|
GasLock string `query:"acc-gas-lock"`
|
||||||
ResetGasQuota string `query:"reset-gas-quota"`
|
GasUnlock string `query:"acc-gas-unlock"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ func (s *Sub) processEventHandler(ctx context.Context, msg *nats.Msg) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cu.Store.ResetGasQuota(ctx, chainEvent.To); err != nil {
|
if err := s.cu.Store.GasUnlock(ctx, chainEvent.To); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "CHAIN.gas":
|
case "CHAIN.gas":
|
||||||
if err := s.cu.Store.ResetGasQuota(ctx, chainEvent.To); err != nil {
|
if err := s.cu.Store.GasUnlock(ctx, chainEvent.To); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,16 +35,6 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, gasQuota, err := cu.Store.GetAccountStatus(ctx, payload.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The user has enough gas for atleast 5 more transactions.
|
|
||||||
if gasQuota > 5 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.CeloProvider.Client.CallCtx(
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
ctx,
|
ctx,
|
||||||
eth.CallFunc(
|
eth.CallFunc(
|
||||||
@ -56,8 +46,8 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The user already requested funds, there is a cooldown applied.
|
// The user recently requested funds, there is a cooldown applied.
|
||||||
// We can schedule an attempt after the cooldown period has passed.
|
// We can schedule an attempt after the cooldown period has passed + 10 seconds.
|
||||||
if nextTime.Int64() > time.Now().Unix() {
|
if nextTime.Int64() > time.Now().Unix() {
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
ctx,
|
ctx,
|
||||||
@ -66,7 +56,7 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
&tasker.Task{
|
&tasker.Task{
|
||||||
Payload: t.Payload(),
|
Payload: t.Payload(),
|
||||||
},
|
},
|
||||||
asynq.ProcessAt(time.Unix(nextTime.Int64(), 0)),
|
asynq.ProcessAt(time.Unix(nextTime.Int64()+10, 0)),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -130,6 +120,7 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
InputData: input,
|
InputData: input,
|
||||||
GasFeeCap: celoutils.SafeGasFeeCap,
|
GasFeeCap: celoutils.SafeGasFeeCap,
|
||||||
GasTipCap: celoutils.SafeGasTipCap,
|
GasTipCap: celoutils.SafeGasTipCap,
|
||||||
|
GasLimit: gasLimit,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
networkBalance big.Int
|
||||||
payload TransferPayload
|
payload TransferPayload
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -105,7 +107,10 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cu.Store.DecrGasQuota(ctx, payload.From); err != nil {
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
|
ctx,
|
||||||
|
eth.Balance(celoutils.HexToAddress(payload.From), nil).Returns(&networkBalance),
|
||||||
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +142,11 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !balanceCheck(networkBalance) {
|
||||||
|
if err := cu.Store.GasLock(ctx, payload.From); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
ctx,
|
ctx,
|
||||||
tasker.AccountRefillGasTask,
|
tasker.AccountRefillGasTask,
|
||||||
@ -148,6 +158,7 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package task
|
package task
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bsm/redislock"
|
"github.com/bsm/redislock"
|
||||||
@ -14,6 +15,15 @@ const (
|
|||||||
lockTimeout = 1 * time.Second
|
lockTimeout = 1 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 20 gwei = max gas price we are willing to pay
|
||||||
|
// 250k = max gas limit
|
||||||
|
// minGasBalanceRequired is optimistic that the immidiate next transfer request will be successful
|
||||||
|
// but the subsequent one could fail (though low probability), therefore we can trigger a gas lock.
|
||||||
|
// Therefore our system wide threshold is 0.01 CELO or 10000000000000000 gas units
|
||||||
|
minGasBalanceRequired = big.NewInt(20000000000 * 250000 * 2)
|
||||||
|
)
|
||||||
|
|
||||||
// lockRetry will at most try to obtain the lock 20 times within ~0.5s.
|
// lockRetry will at most try to obtain the lock 20 times within ~0.5s.
|
||||||
// it is expected to prevent immidiate requeue of the task at the expense of more redis calls.
|
// it is expected to prevent immidiate requeue of the task at the expense of more redis calls.
|
||||||
func lockRetry() redislock.RetryStrategy {
|
func lockRetry() redislock.RetryStrategy {
|
||||||
@ -22,3 +32,8 @@ func lockRetry() redislock.RetryStrategy {
|
|||||||
20,
|
20,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// balanceCheck compares the network balance with the system set min as threshold to execute a transfer.
|
||||||
|
func balanceCheck(networkBalance big.Int) bool {
|
||||||
|
return minGasBalanceRequired.Cmp(&networkBalance) < 0
|
||||||
|
}
|
||||||
|
34
migrations/005_remove_gas_quota.sql
Normal file
34
migrations/005_remove_gas_quota.sql
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
-- Replace gas_quota with gas_lock which checks network balance threshold
|
||||||
|
DROP TRIGGER IF EXISTS update_gas_quota_timestamp ON gas_quota;
|
||||||
|
DROP TABLE IF EXISTS gas_quota_meta;
|
||||||
|
DROP TABLE IF EXISTS gas_quota;
|
||||||
|
DROP TRIGGER IF EXISTS insert_gas_quota ON keystore;
|
||||||
|
DROP FUNCTION IF EXISTS insert_gas_quota;
|
||||||
|
|
||||||
|
-- Gas lock table
|
||||||
|
-- A gas_locked account indicates gas balance is below threshold awaiting next available top up
|
||||||
|
CREATE TABLE IF NOT EXISTS gas_lock (
|
||||||
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
key_id INT REFERENCES keystore(id) NOT NULL,
|
||||||
|
lock BOOLEAN DEFAULT true,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
create function insert_gas_lock()
|
||||||
|
returns trigger
|
||||||
|
as $$
|
||||||
|
begin
|
||||||
|
insert into gas_lock (key_id) values (new.id);
|
||||||
|
return new;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
create trigger insert_gas_lock
|
||||||
|
after insert on keystore
|
||||||
|
for each row
|
||||||
|
execute procedure insert_gas_lock();
|
||||||
|
|
||||||
|
create trigger update_gas_lock_timestamp
|
||||||
|
before update on gas_lock
|
||||||
|
for each row
|
||||||
|
execute procedure update_timestamp();
|
21
queries.sql
21
queries.sql
@ -73,27 +73,24 @@ UPDATE otx_dispatch SET "status" = $2, "block" = $3 WHERE otx_dispatch.id = (
|
|||||||
UPDATE keystore SET active = true WHERE public_key=$1
|
UPDATE keystore SET active = true WHERE public_key=$1
|
||||||
|
|
||||||
--name: get-account-status-by-address
|
--name: get-account-status-by-address
|
||||||
-- Gets current gas quota for an individual account by address
|
-- Gets current gas lock and activation status for an individual account by address
|
||||||
-- $1: public_key
|
-- $1: public_key
|
||||||
SELECT keystore.active, gas_quota.quota FROM keystore
|
SELECT keystore.active, gas_lock.lock FROM keystore
|
||||||
INNER JOIN gas_quota ON keystore.id = gas_quota.key_id
|
INNER JOIN gas_lock ON keystore.id = gas_lock.key_id
|
||||||
WHERE keystore.public_key=$1
|
WHERE keystore.public_key=$1
|
||||||
|
|
||||||
--name: decr-gas-quota
|
--name: acc-gas-lock
|
||||||
-- Consumes a gas quota
|
-- Locks an account for gas reasons
|
||||||
-- $1: public_key
|
-- $1: public_key
|
||||||
UPDATE gas_quota SET quota = quota - 1 WHERE key_id = (
|
UPDATE gas_lock SET lock = true WHERE key_id = (
|
||||||
SELECT id FROM keystore
|
SELECT id FROM keystore
|
||||||
WHERE public_key=$1
|
WHERE public_key=$1
|
||||||
)
|
)
|
||||||
|
|
||||||
--name: reset-gas-quota
|
--name: acc-gas-unlock
|
||||||
-- Resets the gas quota
|
-- Unlocks an account for gas reasons
|
||||||
-- 25 is the agreed upon quota
|
|
||||||
-- $1: public_key
|
-- $1: public_key
|
||||||
UPDATE gas_quota SET quota = gas_quota_meta.default_quota
|
UPDATE gas_lock SET lock = false WHERE key_id = (
|
||||||
FROM gas_quota_meta
|
|
||||||
WHERE key_id = (
|
|
||||||
SELECT id FROM keystore
|
SELECT id FROM keystore
|
||||||
WHERE public_key=$1
|
WHERE public_key=$1
|
||||||
)
|
)
|
Loading…
Reference in New Issue
Block a user