Browse Source

Merge pull request #273 from hermeznetwork/feature/api-test

API state endpoint test
feature/sql-semaphore1
Toni Ramírez 3 years ago
committed by GitHub
parent
commit
37b82604da
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 351 additions and 271 deletions
  1. +10
    -1
      api/api_test.go
  2. +0
    -37
      api/dbtoapistructs.go
  3. +27
    -0
      api/parsers.go
  4. +8
    -7
      api/state.go
  5. +59
    -2
      api/state_test.go
  6. +239
    -218
      api/swagger.yml
  7. +5
    -5
      common/ethrollup.go
  8. +1
    -0
      db/historydb/historydb_test.go
  9. +2
    -1
      db/migrations/0001.sql

+ 10
- 1
api/api_test.go

@ -284,14 +284,23 @@ func TestMain(m *testing.M) {
testBids := genTestBids(blocks, coordinators, bids)
// Vars
var defaultSlotSetBid [6]*big.Int = [6]*big.Int{big.NewInt(10), big.NewInt(10), big.NewInt(10), big.NewInt(10), big.NewInt(10), big.NewInt(10)}
auctionVars := common.AuctionVariables{
EthBlockNum: int64(2),
DonationAddress: ethCommon.HexToAddress("0x1111111111111111111111111111111111111111"),
DefaultSlotSetBid: defaultSlotSetBid,
Outbidding: uint16(1),
SlotDeadline: uint8(20),
BootCoordinator: ethCommon.HexToAddress("0x1111111111111111111111111111111111111111"),
ClosedAuctionSlots: uint16(2),
OpenAuctionSlots: uint16(5),
}
rollupVars := common.RollupVariables{
WithdrawalDelay: uint64(3000),
EthBlockNum: int64(3),
FeeAddToken: big.NewInt(100),
ForgeL1L2BatchTimeout: int64(44),
WithdrawalDelay: uint64(3000),
}
wdelayerVars := common.WDelayerVariables{

+ 0
- 37
api/dbtoapistructs.go

@ -1,37 +0,0 @@
package api
import (
"encoding/base64"
"strconv"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common"
"github.com/iden3/go-iden3-crypto/babyjub"
)
const exitIdx = "hez:EXIT:1"
type errorMsg struct {
Message string
}
func bjjToString(bjj *babyjub.PublicKey) string {
pkComp := [32]byte(bjj.Compress())
sum := pkComp[0]
for i := 1; i < len(pkComp); i++ {
sum += pkComp[i]
}
bjjSum := append(pkComp[:], sum)
return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
}
func ethAddrToHez(addr ethCommon.Address) string {
return "hez:" + addr.String()
}
func idxToHez(idx common.Idx, tokenSymbol string) string {
if idx == 1 {
return exitIdx
}
return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
}

+ 27
- 0
api/parsers.go

@ -13,6 +13,8 @@ import (
"github.com/iden3/go-iden3-crypto/babyjub"
)
const exitIdx = "hez:EXIT:1"
// Query parsers
type querier interface {
@ -428,3 +430,28 @@ func parseParamHezEthAddr(c paramer) (*ethCommon.Address, error) {
addrStr := c.Param(name)
return hezStringToEthAddr(addrStr, name)
}
type errorMsg struct {
Message string
}
func bjjToString(bjj *babyjub.PublicKey) string {
pkComp := [32]byte(bjj.Compress())
sum := pkComp[0]
for i := 1; i < len(pkComp); i++ {
sum += pkComp[i]
}
bjjSum := append(pkComp[:], sum)
return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
}
func ethAddrToHez(addr ethCommon.Address) string {
return "hez:" + addr.String()
}
func idxToHez(idx common.Idx, tokenSymbol string) string {
if idx == 1 {
return exitIdx
}
return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
}

+ 8
- 7
api/state.go

@ -20,17 +20,17 @@ type Network struct {
// NextForger is a representation of the information of a coordinator and the period will forge
type NextForger struct {
Coordinator historydb.CoordinatorAPI
Period Period
Coordinator historydb.CoordinatorAPI `json:"coordinator"`
Period Period `json:"period"`
}
// Period is a representation of a period
type Period struct {
SlotNum int64
FromBlock int64
ToBlock int64
FromTimestamp time.Time
ToTimestamp time.Time
SlotNum int64 `json:"slotNum"`
FromBlock int64 `json:"fromBlock"`
ToBlock int64 `json:"toBlock"`
FromTimestamp time.Time `json:"fromTimestamp"`
ToTimestamp time.Time `json:"toTimestamp"`
}
var bootCoordinator historydb.CoordinatorAPI = historydb.CoordinatorAPI{
@ -41,6 +41,7 @@ var bootCoordinator historydb.CoordinatorAPI = historydb.CoordinatorAPI{
}
func (a *API) getState(c *gin.Context) {
// TODO: There are no events for the buckets information, so now this information will be 0
c.JSON(http.StatusOK, a.status)
}

+ 59
- 2
api/state_test.go

@ -5,11 +5,28 @@ import (
"time"
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db/historydb"
"github.com/stretchr/testify/assert"
)
const secondsPerBlock = 15
type testStatus struct {
Network testNetwork `json:"network"`
Metrics historydb.Metrics `json:"metrics"`
Rollup common.RollupVariables `json:"rollup"`
Auction common.AuctionVariables `json:"auction"`
WithdrawalDelayer common.WDelayerVariables `json:"withdrawalDelayer"`
RecommendedFee common.RecommendedFee `json:"recommendedFee"`
}
type testNetwork struct {
LastBlock int64 `json:"lastBlock"`
LastBatch testBatch `json:"lastBatch"`
CurrentSlot int64 `json:"currentSlot"`
NextForgers []NextForger `json:"nextForgers"`
}
func TestSetRollupVariables(t *testing.T) {
rollupVars := &common.RollupVariables{}
assert.Equal(t, *rollupVars, api.status.Rollup)
@ -101,6 +118,46 @@ func TestUpdateRecommendedFee(t *testing.T) {
err := api.UpdateRecommendedFee()
assert.NoError(t, err)
assert.Greater(t, api.status.RecommendedFee.ExistingAccount, float64(0))
assert.Equal(t, api.status.RecommendedFee.CreatesAccount, api.status.RecommendedFee.ExistingAccount*createAccountExtraFeePercentage)
assert.Equal(t, api.status.RecommendedFee.CreatesAccountAndRegister, api.status.RecommendedFee.ExistingAccount*createAccountInternalExtraFeePercentage)
assert.Equal(t, api.status.RecommendedFee.CreatesAccount,
api.status.RecommendedFee.ExistingAccount*createAccountExtraFeePercentage)
assert.Equal(t, api.status.RecommendedFee.CreatesAccountAndRegister,
api.status.RecommendedFee.ExistingAccount*createAccountInternalExtraFeePercentage)
}
func TestGetStatus(t *testing.T) {
lastBlock := tc.blocks[3]
lastBatchNum := common.BatchNum(3)
currentSlotNum := int64(1)
api.SetRollupVariables(tc.rollupVars)
api.SetWDelayerVariables(tc.wdelayerVars)
api.SetAuctionVariables(tc.auctionVars)
err := api.UpdateNetworkInfo(lastBlock, lastBatchNum, currentSlotNum)
assert.NoError(t, err)
err = api.UpdateMetrics()
assert.NoError(t, err)
err = api.UpdateRecommendedFee()
assert.NoError(t, err)
endpoint := apiURL + "state"
var status testStatus
assert.NoError(t, doGoodReq("GET", endpoint, nil, &status))
assert.Equal(t, tc.rollupVars, status.Rollup)
assert.Equal(t, tc.auctionVars, status.Auction)
assert.Equal(t, tc.wdelayerVars, status.WithdrawalDelayer)
assert.Equal(t, lastBlock.EthBlockNum, status.Network.LastBlock)
assert.Equal(t, lastBatchNum, status.Network.LastBatch.BatchNum)
assert.Equal(t, currentSlotNum, status.Network.CurrentSlot)
assert.Equal(t, int(api.status.Auction.ClosedAuctionSlots)+1, len(status.Network.NextForgers))
assert.Greater(t, status.Metrics.TransactionsPerBatch, float64(0))
assert.Greater(t, status.Metrics.BatchFrequency, float64(0))
assert.Greater(t, status.Metrics.TransactionsPerBatch, float64(0))
assert.Greater(t, status.Metrics.TotalAccounts, int64(0))
assert.Greater(t, status.Metrics.TotalBJJs, int64(0))
assert.Greater(t, status.Metrics.AvgTransactionFee, float64(0))
assert.Greater(t, status.RecommendedFee.ExistingAccount, float64(0))
assert.Equal(t, status.RecommendedFee.CreatesAccount,
status.RecommendedFee.ExistingAccount*createAccountExtraFeePercentage)
assert.Equal(t, status.RecommendedFee.CreatesAccountAndRegister,
status.RecommendedFee.ExistingAccount*createAccountInternalExtraFeePercentage)
}

+ 239
- 218
api/swagger.yml

@ -2273,6 +2273,8 @@ components:
type: object
description: Time period in which the coordinator will have the ability to forge. Specified both in Ethereum blocks and timestamp
properties:
slotNum:
$ref: '#/components/schemas/SlotNum'
fromBlock:
$ref: '#/components/schemas/EthBlockNum'
toBlock:
@ -2283,242 +2285,261 @@ components:
toTimestamp:
type: string
format: date-time
required:
- slotNum
- fromBlock
- toBlock
- fromTimestamp
- toTimestamp
additionalProperties: false
required:
- coordinator
- period
additionalProperties: false
NextForgers:
type: object
properties:
nextForgers:
type: array
description: List of next coordinators to forge.
items:
$ref: '#/components/schemas/NextForger'
pendingItems:
$ref: '#/components/schemas/PendingItems'
type: array
description: List of next coordinators to forge.
items:
$ref: '#/components/schemas/NextForger'
State:
type: object
description: Gobal variables of the network
properties:
network:
type: object
description: Gobal statistics of the network
properties:
lastBlock:
allOf:
- $ref: '#/components/schemas/EthBlockNum'
- description: Last synchronized Etherum block.
- example: 3457437
lastBatch:
$ref: '#/components/schemas/Batch'
currentSlot:
allOf:
- $ref: '#/components/schemas/SlotNum'
- description: Slot where batches are currently being forged.
- example: 2334
nextForgers:
$ref: '#/components/schemas/NextForgers'
additionalProperties: false
require:
- lastBlock
- lastBatch
- currentSlot
- nextForgers
$ref: '#/components/schemas/StateNetwork'
metrics:
type: object
description: Metrics of the network
properties:
transactionsPerBatch:
type: number
description: Average transactions per batch in the last 24 hours.
example: 2002.7
batchFrequency:
type: number
description: Average elapsed time between batches in the last 24 hours, in seconds.
example: 8.9
transactionsPerSecond:
type: number
description: Average transactions per second in the last 24 hours.
example: 302.3
totalAccounts:
type: integer
description: Number of created accounts.
example: 90473
totalBJJs:
type: integer
description: Number of different registered BJJs.
example: 23067
avgTransactionFee:
type: number
description: Average fee percentage paid for L2 transactions in the last 24 hours.
example: 1.54
additionalProperties: false
require:
- transactionsPerBatch
- batchFrequency
- transactionsPerSecond
- totalAccounts
- totalBJJs
- avgTransactionFee
$ref: '#/components/schemas/StateMetrics'
rollup:
type: object
description: Rollup parameters
properties:
forgeL1L2BatchTimeout:
type: integer
description: Max ethereum blocks after the last L1-L2-batch, when exceeds the timeout only L1-L2-batch are allowed.
example: 5
feeAddToken:
type: integer
description: Fee to pay when registering tokens into the network.
example: 5698
withdrawalDelay:
type: integer
description: Withdraw delay in seconds
example: 432000
buckets:
type: array
description: List of buckets state
items:
type: object
properties:
ceilUSD:
type: integer
description: Max USD value
example: 1000
blockStamp:
type: integer
description: Last time a withdrawal was added ( or removed if the bucket was full)
example: 4475934
withdrawals:
type: integer
description: Available withdrawals of the bucket
example: 4
blockWithdrawalRate:
type: integer
description: Every `blockWithdrawalRate` blocks add 1 withdrawal
example: 8
maxWithdrawals:
type: integer
description: Max withdrawals the bucket can hold
example: 4
additionalProperties: false
require:
- ceilUSD
- blockStamp
- withdrawals
- blockWithdrawalRate
- maxWithdrawals
additionalProperties: false
require:
- forgeL1L2BatchTimeout
- feeAddToken
- withdrawalDelay
- buckets
$ref: '#/components/schemas/StateRollup'
auction:
type: object
description: Auction parameters.
properties:
bootCoordinator:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address of the boot coordinator.
- example: "0x997dc4262BCDbf85190C01c996b4C06a461d2430"
slotDeadline:
type: integer
description: Number of blocks after the beginning of a slot after which any coordinator can forge if the winner has not forged any batch in that slot.
example: 3
closedAuctionSlots:
type: integer
description: Amount of slots between the current slot and the slot auction that is closed. Example if the value is 2, when slot 10 begins, the auction of the slot 12 gets closed.
example: 2
openAuctionSlots:
type: integer
description: How many days in advance are auctions opened.
defaultSlotSetBid:
type: array
description: "Initial minimal bid for each auction. Expressed as an array of 6 values. To calculate which value corresponds to each slot: `initialMinimalBidding[slotNum%6]`."
items:
type: integer
example: [32,0,68,21,55,99]
outbidding:
type: number
description: Minimum outbid over the previous one to consider it valid.
example: 3.64
donationAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address where the donations will go to.
- example: "0x887dc4262BCDbf85190C01c996b4C06a461d2430"
allocationRatio:
type: array
description: Percentage in which fees will be splitted between donations, governance and burning. The sum of the tree values should be 100.
items:
type: integer
example: [80,10,10]
additionalProperties: false
require:
- bootCoordinator
- slotDeadline
- closedAuctionSlots
- openAuctionSlots
- defaultSlotSetBid
- outbidding
- donationAddress
- allocationRatio
$ref: '#/components/schemas/StateAuction'
withdrawalDelayer:
type: object
description: Withdrawal delayer parameters
properties:
hermezRollupAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address of the rollup smart contract.
- example: "0x777dc4262BCDbf85190C01c996b4C06a461d2430"
hermezGovernanceDAOAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address of the governance DAO.
- example: "0x667dc4262BCDbf85190C01c996b4C06a461d2430"
whiteHackGroupAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum Address that can claim the funds in an emergency when the maximum emergency mode time is exceeded.
- example: "0x557dc4262BCDbf85190C01c996b4C06a461d2430"
hermezKeeperAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum Address that can enable emergency mode and modify the delay to make a withdrawal.
- example: "0x557dc4262BCDbf85190C01c996b4C06a461d2430"
withdrawalDelay:
allOf:
- $ref: '#/components/schemas/EthBlockNum'
- description: The time that anyone needs to wait until a withdrawal of the funds is allowed, in seconds.
- example: 539573849
emergencyModeStartingTime:
type: integer
description: Second (since unix epoch) in which the emergency mode has been activated.
example: 10
emergencyMode:
type: boolean
description: Indicates if emergency mode has been activated.
example: false
additionalProperties: false
require:
- hermezRollupAddress
- hermezGovernanceDAOAddress
- whiteHackGroupAddress
- hermezKeeperAddress
- withdrawalDelay
- emergencyModeStartingTime
- emergencyMode
$ref: '#/components/schemas/StateWithdrawDelayer'
recommendedFee:
$ref: '#/components/schemas/RecommendedFee'
additionalProperties: false
require:
required:
- network
- metrics
- rollup
- auction
- withdrawalDelayer
- recomendedFee
- recommendedFee
StateNetwork:
type: object
description: Gobal statistics of the network
properties:
lastBlock:
allOf:
- $ref: '#/components/schemas/EthBlockNum'
- description: Last synchronized Etherum block.
- example: 3457437
lastBatch:
$ref: '#/components/schemas/Batch'
currentSlot:
allOf:
- $ref: '#/components/schemas/SlotNum'
- description: Slot where batches are currently being forged.
- example: 2334
nextForgers:
$ref: '#/components/schemas/NextForgers'
additionalProperties: false
required:
- lastBlock
- lastBatch
- currentSlot
- nextForgers
StateAuction:
type: object
description: Auction parameters.
properties:
ethereumBlockNum:
$ref: '#/components/schemas/EthBlockNum'
bootCoordinator:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address of the boot coordinator.
- example: "0x997dc4262BCDbf85190C01c996b4C06a461d2430"
slotDeadline:
type: integer
description: Number of blocks after the beginning of a slot after which any coordinator can forge if the winner has not forged any batch in that slot.
example: 3
closedAuctionSlots:
type: integer
description: Amount of slots between the current slot and the slot auction that is closed. Example if the value is 2, when slot 10 begins, the auction of the slot 12 gets closed.
example: 2
openAuctionSlots:
type: integer
description: How many days in advance are auctions opened.
defaultSlotSetBid:
type: array
description: "Initial minimal bid for each auction. Expressed as an array of 6 values. To calculate which value corresponds to each slot: `initialMinimalBidding[slotNum%6]`."
items:
type: integer
example: [32,0,68,21,55,99]
outbidding:
type: number
description: Minimum outbid over the previous one to consider it valid.
example: 3.64
donationAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address where the donations will go to.
- example: "0x887dc4262BCDbf85190C01c996b4C06a461d2430"
allocationRatio:
type: array
description: Percentage in which fees will be splitted between donations, governance and burning. The sum of the tree values should be 100.
items:
type: integer
example: [80,10,10]
additionalProperties: false
required:
- ethereumBlockNum
- bootCoordinator
- slotDeadline
- closedAuctionSlots
- openAuctionSlots
- defaultSlotSetBid
- outbidding
- donationAddress
- allocationRatio
StateRollup:
type: object
description: Rollup parameters
properties:
ethereumBlockNum:
$ref: '#/components/schemas/EthBlockNum'
forgeL1L2BatchTimeout:
type: integer
description: Max ethereum blocks after the last L1-L2-batch, when exceeds the timeout only L1-L2-batch are allowed.
example: 5
feeAddToken:
type: integer
description: Fee to pay when registering tokens into the network.
example: 5698
withdrawalDelay:
type: integer
description: Withdraw delay in seconds
example: 432000
buckets:
type: array
description: List of buckets state
items:
type: object
properties:
ceilUSD:
type: integer
description: Max USD value
example: 1000
blockStamp:
type: integer
description: Last time a withdrawal was added ( or removed if the bucket was full)
example: 4475934
withdrawals:
type: integer
description: Available withdrawals of the bucket
example: 4
blockWithdrawalRate:
type: integer
description: Every `blockWithdrawalRate` blocks add 1 withdrawal
example: 8
maxWithdrawals:
type: integer
description: Max withdrawals the bucket can hold
example: 4
additionalProperties: false
required:
- ceilUSD
- blockStamp
- withdrawals
- blockWithdrawalRate
- maxWithdrawals
additionalProperties: false
required:
- ethereumBlockNum
- forgeL1L2BatchTimeout
- feeAddToken
- withdrawalDelay
- buckets
StateWithdrawDelayer:
type: object
description: Withdrawal delayer parameters
properties:
ethereumBlockNum:
$ref: '#/components/schemas/EthBlockNum'
hermezGovernanceDAOAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum address of the governance DAO.
- example: "0x667dc4262BCDbf85190C01c996b4C06a461d2430"
whiteHackGroupAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum Address that can claim the funds in an emergency when the maximum emergency mode time is exceeded.
- example: "0x557dc4262BCDbf85190C01c996b4C06a461d2430"
hermezKeeperAddress:
allOf:
- $ref: '#/components/schemas/EthereumAddress'
- description: Ethereum Address that can enable emergency mode and modify the delay to make a withdrawal.
- example: "0x557dc4262BCDbf85190C01c996b4C06a461d2430"
withdrawalDelay:
allOf:
- $ref: '#/components/schemas/EthBlockNum'
- description: The time that anyone needs to wait until a withdrawal of the funds is allowed, in seconds.
- example: 539573849
emergencyModeStartingTime:
type: integer
description: Second (since unix epoch) in which the emergency mode has been activated.
example: 10
emergencyMode:
type: boolean
description: Indicates if emergency mode has been activated.
example: false
additionalProperties: false
required:
- ethereumBlockNum
- hermezGovernanceDAOAddress
- whiteHackGroupAddress
- hermezKeeperAddress
- withdrawalDelay
- emergencyModeStartingTime
- emergencyMode
StateMetrics:
type: object
description: Metrics of the network
properties:
transactionsPerBatch:
type: number
description: Average transactions per batch in the last 24 hours.
example: 2002.7
batchFrequency:
type: number
description: Average elapsed time between batches in the last 24 hours, in seconds.
example: 8.9
transactionsPerSecond:
type: number
description: Average transactions per second in the last 24 hours.
example: 302.3
totalAccounts:
type: integer
description: Number of created accounts.
example: 90473
totalBJJs:
type: integer
description: Number of different registered BJJs.
example: 23067
avgTransactionFee:
type: number
description: Average fee percentage paid for L2 transactions in the last 24 hours.
example: 1.54
additionalProperties: false
required:
- transactionsPerBatch
- batchFrequency
- transactionsPerSecond
- totalAccounts
- totalBJJs
- avgTransactionFee
PendingItems:
type: integer
description: Amount of items that will be returned in subsequent calls to the endpoint, as long as they are done with same filters. When the value is 0 it means that all items have been sent.

+ 5
- 5
common/ethrollup.go

@ -157,9 +157,9 @@ type Bucket struct {
// RollupVariables are the variables of the Rollup Smart Contract
type RollupVariables struct {
EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"`
FeeAddToken *big.Int `json:"feeAddToken" meddler:"fee_add_token,bigint" validate:"required"`
ForgeL1L2BatchTimeout int64 `json:"forgeL1L2BatchTimeout" meddler:"forge_l1_timeout" validate:"required"`
WithdrawalDelay uint64 `json:"withdrawalDelay" meddler:"withdrawal_delay" validate:"required"`
// Buckets [RollupConstNumBuckets]Bucket `json:"buckets" meddler:"buckets,json"`
EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"`
FeeAddToken *big.Int `json:"feeAddToken" meddler:"fee_add_token,bigint" validate:"required"`
ForgeL1L2BatchTimeout int64 `json:"forgeL1L2BatchTimeout" meddler:"forge_l1_timeout" validate:"required"`
WithdrawalDelay uint64 `json:"withdrawalDelay" meddler:"withdrawal_delay" validate:"required"`
Buckets [RollupConstNumBuckets]Bucket `json:"buckets" meddler:"buckets,json"`
}

+ 1
- 0
db/historydb/historydb_test.go

@ -469,6 +469,7 @@ func TestSetInitialSCVars(t *testing.T) {
big.NewInt(10),
12,
13,
[5]common.Bucket{},
}
//nolint:govet
auction := &common.AuctionVariables{

+ 2
- 1
db/migrations/0001.sql

@ -520,7 +520,8 @@ CREATE TABLE rollup_vars (
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
fee_add_token BYTEA NOT NULL,
forge_l1_timeout BYTEA NOT NULL,
withdrawal_delay BIGINT NOT NULL
withdrawal_delay BIGINT NOT NULL,
buckets BYTEA
);
CREATE TABLE auction_vars (

Loading…
Cancel
Save