Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ The `arkd` server can be configured using environment variables.
| `ARKD_LIVE_STORE_TYPE` | Cache service type (redis, inmemory) | `redis` |
| `ARKD_REDIS_URL` | Redis db connection url if `ARKD_LIVE_STORE_TYPE` is set to `redis` | - |
| `ARKD_REDIS_NUM_OF_RETRIES` | Maximum number of retries for Redis write operations in case of conflicts | - |
| `ARKD_VTXO_TREE_EXPIRY` | VTXO tree expiry in seconds | `604672` (7 days) |
| `ARKD_VTXO_TREE_EXPIRY` | VTXO tree expiry in seconds. Values below `512` are allowed only on regtest | `604672` (7 days) |
| `ARKD_UNILATERAL_EXIT_DELAY` | Unilateral exit delay in seconds | `86400` (24 hours) |
| `ARKD_BOARDING_EXIT_DELAY` | Boarding exit delay in seconds | `7776000` (3 months) |
| `ARKD_ESPLORA_URL` | Esplora API URL | `https://blockstream.info/api` |
Expand All @@ -92,7 +92,6 @@ The `arkd` server can be configured using environment variables.
| `ARKD_VTXO_MIN_AMOUNT` | The minimum allowed amount for vtxos | `-1` (dust) |
| `ARKD_BAN_DURATION` | Ban duration in seconds | `300` (5 minutes) |
| `ARKD_BAN_THRESHOLD` | Number of crimes to trigger a ban | `3` |
| `ARKD_SCHEDULER_TYPE` | Scheduler type (gocron, block) | `gocron` |
| `ARKD_CHECKPOINT_EXIT_DELAY` | Checkpoint exit delay in seconds | `86400` (24 hours) |
| `ARKD_TLS_EXTRA_IP` | Extra IP addresses for TLS (comma-separated) | - |
| `ARKD_TLS_EXTRA_DOMAIN` | Extra domains for TLS (comma-separated) | - |
Expand All @@ -105,7 +104,6 @@ The `arkd` server can be configured using environment variables.
| `ARKD_SCHEDULED_SESSION_MAX_ROUND_PARTICIPANTS_COUNT` | Max participants for scheduled sessions | - |
| `ARKD_OTEL_COLLECTOR_ENDPOINT` | OpenTelemetry collector endpoint | - |
| `ARKD_OTEL_PUSH_INTERVAL` | OpenTelemetry push interval in seconds | `10` |
| `ARKD_ALLOW_CSV_BLOCK_TYPE` | Allow CSV block type | `false` |
| `ARKD_HEARTBEAT_INTERVAL` | Heartbeat interval in seconds | `60` |
| `ARKD_ROUND_REPORT_ENABLED` | Enable round report service | `false` |

Expand Down
1 change: 0 additions & 1 deletion docker-compose.regtest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ services:
- ARKD_LOG_LEVEL=6
- ARKD_NO_MACAROONS=true
- ARKD_VTXO_TREE_EXPIRY=20
- ARKD_SCHEDULER_TYPE=block
- ARKD_UNILATERAL_EXIT_DELAY=512
- ARKD_BOARDING_EXIT_DELAY=1024
- ARKD_CHECKPOINT_EXIT_DELAY=10
Expand Down
2 changes: 0 additions & 2 deletions envs/arkd.dev.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ARKD_LOG_LEVEL=5
ARKD_NO_MACAROONS=true
ARKD_SCHEDULER_TYPE=block
ARKD_VTXO_TREE_EXPIRY=20
ARKD_CHECKPOINT_EXIT_DELAY=10
ARKD_UNILATERAL_EXIT_DELAY=512
Expand All @@ -12,7 +11,6 @@ ARKD_PG_DB_AUTOCREATE=true
ARKD_PG_DB_URL=postgresql://postgres@127.0.0.1:5432/projection?sslmode=disable
ARKD_PG_EVENT_DB_URL=postgresql://postgres@127.0.0.1:5432/event?sslmode=disable
ARKD_REDIS_URL=redis://localhost:6379/0
ARKD_ALLOW_CSV_BLOCK_TYPE=true
ARKD_VTXO_MIN_AMOUNT=1
ARKD_BAN_THRESHOLD=1
ARKD_ONCHAIN_OUTPUT_FEE=100
Expand Down
4 changes: 2 additions & 2 deletions envs/arkd.light.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ARKD_LOG_LEVEL=5
ARKD_NO_MACAROONS=true
ARKD_VTXO_TREE_EXPIRY=512
ARKD_UNILATERAL_EXIT_DELAY=512
ARKD_BOARDING_EXIT_DELAY=1024
ARKD_DATADIR=./data/regtest
Expand All @@ -9,8 +8,9 @@ ARKD_WALLET_ADDR=127.0.0.1:6060
ARKD_LIVE_STORE_TYPE=inmemory
ARKD_DB_TYPE=sqlite
ARKD_EVENT_DB_TYPE=badger
ARKD_ALLOW_CSV_BLOCK_TYPE=true
ARKD_SESSION_DURATION=10
ARKD_VTXO_MIN_AMOUNT=1
ARKD_BAN_THRESHOLD=1
ARKD_ONCHAIN_OUTPUT_FEE=100
ARKD_VTXO_TREE_EXPIRY=20
Comment thread
bitcoin-coder-bob marked this conversation as resolved.
Outdated
ARKD_CHECKPOINT_EXIT_DELAY=10
72 changes: 24 additions & 48 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ var (
"sqlite": {},
"postgres": {},
}
supportedSchedulers = supportedType{
"gocron": {},
"block": {},
}
supportedTxBuilders = supportedType{
"covenantless": {},
}
Expand Down Expand Up @@ -82,7 +78,6 @@ type Config struct {
SessionDuration int64
BanDuration int64
BanThreshold int64 // number of crimes to trigger a ban
SchedulerType string
TxBuilderType string
LiveStoreType string
RedisUrl string
Expand All @@ -95,7 +90,6 @@ type Config struct {
CheckpointExitDelay arklib.RelativeLocktime
BoardingExitDelay arklib.RelativeLocktime
NoteUriPrefix string
AllowCSVBlockType bool
HeartbeatInterval int64

VtxoNoCsvValidationCutoffDate int64
Expand Down Expand Up @@ -175,7 +169,6 @@ var (
DbUrl = "PG_DB_URL"
PostgresAutoCreateDB = "PG_DB_AUTOCREATE"
EventDbUrl = "PG_EVENT_DB_URL"
SchedulerType = "SCHEDULER_TYPE"
TxBuilderType = "TX_BUILDER_TYPE"
LiveStoreType = "LIVE_STORE_TYPE"
RedisUrl = "REDIS_URL"
Expand Down Expand Up @@ -212,7 +205,6 @@ var (
VtxoMaxAmount = "VTXO_MAX_AMOUNT"
UtxoMinAmount = "UTXO_MIN_AMOUNT"
VtxoMinAmount = "VTXO_MIN_AMOUNT"
AllowCSVBlockType = "ALLOW_CSV_BLOCK_TYPE"
HeartbeatInterval = "HEARTBEAT_INTERVAL"
RoundReportServiceEnabled = "ROUND_REPORT_ENABLED"
SettlementMinExpiryGap = "SETTLEMENT_MIN_EXPIRY_GAP"
Expand All @@ -234,7 +226,6 @@ var (
DefaultAdminPort = 7071
defaultDbType = "postgres"
defaultEventDbType = "postgres"
defaultSchedulerType = "gocron"
defaultTxBuilderType = "covenantless"
defaultLiveStoreType = "redis"
defaultRedisTxNumOfRetries = 10
Expand All @@ -251,7 +242,6 @@ var (
defaultUtxoMinAmount = -1 // -1 means native dust limit (default)
defaultVtxoMinAmount = -1 // -1 means native dust limit (default)
defaultVtxoMaxAmount = -1 // -1 means no limit (default)
defaultAllowCSVBlockType = false

defaultRoundMaxParticipantsCount = 128
defaultRoundMinParticipantsCount = 1
Expand Down Expand Up @@ -281,7 +271,6 @@ func LoadConfig() (*Config, error) {
viper.SetDefault(BanDuration, defaultBanDuration)
viper.SetDefault(BanThreshold, defaultBanThreshold)
viper.SetDefault(VtxoTreeExpiry, defaultVtxoTreeExpiry)
viper.SetDefault(SchedulerType, defaultSchedulerType)
viper.SetDefault(EventDbType, defaultEventDbType)
viper.SetDefault(TxBuilderType, defaultTxBuilderType)
viper.SetDefault(UnilateralExitDelay, defaultUnilateralExitDelay)
Expand All @@ -299,7 +288,6 @@ func LoadConfig() (*Config, error) {
viper.SetDefault(VtxoMinAmount, defaultVtxoMinAmount)
viper.SetDefault(LiveStoreType, defaultLiveStoreType)
viper.SetDefault(RedisTxNumOfRetries, defaultRedisTxNumOfRetries)
viper.SetDefault(AllowCSVBlockType, defaultAllowCSVBlockType)
viper.SetDefault(OtelPushInterval, defaultOtelPushInterval)
viper.SetDefault(HeartbeatInterval, defaultHeartbeatInterval)
viper.SetDefault(RoundReportServiceEnabled, defaultRoundReportServiceEnabled)
Expand Down Expand Up @@ -341,11 +329,6 @@ func LoadConfig() (*Config, error) {
}
}

allowCSVBlockType := viper.GetBool(AllowCSVBlockType)
if viper.GetString(SchedulerType) == "block" {
allowCSVBlockType = true
}

signerAddr := viper.GetString(SignerAddr)
if signerAddr == "" {
signerAddr = viper.GetString(WalletAddr)
Expand All @@ -368,7 +351,6 @@ func LoadConfig() (*Config, error) {
AdminPort: adminPort,
EventDbType: viper.GetString(EventDbType),
DbType: viper.GetString(DbType),
SchedulerType: viper.GetString(SchedulerType),
TxBuilderType: viper.GetString(TxBuilderType),
LiveStoreType: viper.GetString(LiveStoreType),
RedisUrl: redisUrl,
Expand Down Expand Up @@ -416,7 +398,6 @@ func LoadConfig() (*Config, error) {
UtxoMinAmount: viper.GetInt64(UtxoMinAmount),
VtxoMaxAmount: viper.GetInt64(VtxoMaxAmount),
VtxoMinAmount: viper.GetInt64(VtxoMinAmount),
AllowCSVBlockType: allowCSVBlockType,
RoundReportServiceEnabled: viper.GetBool(RoundReportServiceEnabled),
SettlementMinExpiryGap: viper.GetInt64(SettlementMinExpiryGap),
MaxTxWeight: viper.GetUint64(MaxTxWeight),
Expand Down Expand Up @@ -459,12 +440,6 @@ func (c *Config) Validate() error {
if !supportedDbs.supports(c.DbType) {
return fmt.Errorf("db type not supported, please select one of: %s", supportedDbs)
}
if !supportedSchedulers.supports(c.SchedulerType) {
return fmt.Errorf(
"scheduler type not supported, please select one of: %s",
supportedSchedulers,
)
}
if !supportedTxBuilders.supports(c.TxBuilderType) {
return fmt.Errorf(
"tx builder type not supported, please select one of: %s",
Expand Down Expand Up @@ -492,24 +467,7 @@ func (c *Config) Validate() error {
if c.BanThreshold < 1 {
log.Debugf("autoban is disabled")
}
if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock {
if c.SchedulerType != "block" {
return fmt.Errorf(
"scheduler type must be block if vtxo tree expiry is expressed in blocks",
)
}
if !c.AllowCSVBlockType {
return fmt.Errorf(
"CSV block type must be allowed if vtxo tree expiry is expressed in blocks",
)
}
} else { // seconds
if c.SchedulerType != "gocron" {
return fmt.Errorf(
"scheduler type must be gocron if vtxo tree expiry is expressed in seconds",
)
}

if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeSecond {
// vtxo tree expiry must be a multiple of 512 if expressed in seconds
if c.VtxoTreeExpiry.Value%minAllowedSequence != 0 {
c.VtxoTreeExpiry.Value -= c.VtxoTreeExpiry.Value % minAllowedSequence
Expand Down Expand Up @@ -539,6 +497,11 @@ func (c *Config) Validate() error {
)
}

// Ensure vtxo tree expiry and checkpoint exit delay are of the same type
if c.CheckpointExitDelay.Type != c.VtxoTreeExpiry.Type {
return fmt.Errorf("checkpoint and vtxo tree locktimes must be of the same type")
}

if c.CheckpointExitDelay.Type == arklib.LocktimeTypeSecond {
if c.CheckpointExitDelay.Value%minAllowedSequence != 0 {
c.CheckpointExitDelay.Value -= c.CheckpointExitDelay.Value % minAllowedSequence
Expand Down Expand Up @@ -642,6 +605,19 @@ func (c *Config) Validate() error {
if err := c.alertsService(); err != nil {
return err
}

// Enforce that if the network is not regtest, the locktimes must be expressed in seconds.
// These checks must be done after the wallet service is initialized, as it is needed to
// determine the network.
if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock &&
c.network.Name != arklib.BitcoinRegTest.Name {
return fmt.Errorf("vtxo tree expiry expressed in blocks is allowed only on regtest")
}
if c.CheckpointExitDelay.Type == arklib.LocktimeTypeBlock &&
c.network.Name != arklib.BitcoinRegTest.Name {
return fmt.Errorf("checkpoint exit delay expressed in blocks is allowed only on regtest")
}

return nil
}

Expand Down Expand Up @@ -825,10 +801,10 @@ func (c *Config) liveStoreService() error {
func (c *Config) schedulerService() error {
var svc ports.SchedulerService
var err error
switch c.SchedulerType {
case "gocron":
switch c.VtxoTreeExpiry.Type {
case arklib.LocktimeTypeSecond:
svc = timescheduler.NewScheduler()
case "block":
case arklib.LocktimeTypeBlock:
svc, err = blockscheduler.NewScheduler(c.EsploraURL)
default:
err = fmt.Errorf("unknown scheduler type")
Expand Down Expand Up @@ -861,11 +837,11 @@ func (c *Config) appService() error {
if err := c.txBuilderService(); err != nil {
return err
}

roundReportSvc, err := c.RoundReportService()
if err != nil {
return err
}
allowCSVBlockType := c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock
Comment thread
louisinger marked this conversation as resolved.
Outdated

svc, err := application.NewService(
c.wallet, c.signer, c.repo, c.txBuilder, c.scanner,
Expand All @@ -875,7 +851,7 @@ func (c *Config) appService() error {
c.SessionDuration, c.RoundMinParticipantsCount, c.RoundMaxParticipantsCount,
c.UtxoMaxAmount, c.UtxoMinAmount, c.VtxoMaxAmount, c.VtxoMinAmount,
c.BanDuration, c.BanThreshold, c.MaxTxWeight, c.AssetTxMaxWeightRatio,
*c.network, c.AllowCSVBlockType, c.NoteUriPrefix,
*c.network, allowCSVBlockType, c.NoteUriPrefix,
ssStartTime, ssEndTime, ssPeriod, ssDuration,
c.ScheduledSessionMinRoundParticipantsCount, c.ScheduledSessionMaxRoundParticipantsCount,
c.SettlementMinExpiryGap,
Expand Down
17 changes: 17 additions & 0 deletions internal/core/application/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,23 @@ func (s *service) registerEventHandlers() {
return
}

// Make sure to mark new vtxos as swept if any of the spent inputs is swept as well or
// expired
sweptIns := false
now := time.Now()
Comment thread
bitcoin-coder-bob marked this conversation as resolved.
Outdated
for _, vtxo := range spentVtxos {
if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) {
sweptIns = true
break
}
}

if sweptIns {
for i := range newVtxos {
newVtxos[i].Swept = true
}
}

checkpointTxsByOutpoint := make(map[string]TxData)
for txid, tx := range offchainTx.CheckpointTxs {
// nolint
Expand Down
16 changes: 14 additions & 2 deletions internal/infrastructure/db/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,15 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event)
return
}

txSwept := false
batch, err := s.roundStore.GetRoundWithCommitmentTxid(ctx, offchainTx.RootCommitmentTxId)
// We consider the tx swept if:
// - there is an error fetching the batch (this is just fallback, should never happen)
// - the batch is swept
// - the tx expired (meaning one or all its inputs expired and are already swept or about
// to be swept)
txSwept = err != nil || (batch != nil && len(batch.SweepTxs) > 0) ||
Comment thread
bitcoin-coder-bob marked this conversation as resolved.
time.Now().After(time.Unix(offchainTx.ExpiryTimestamp, 0))
// once the offchain tx is finalized, the user signed the checkpoint txs
// thus, we can create the new vtxos in the db.
newVtxos := make([]domain.Vtxo, 0, len(outs))
Expand All @@ -548,7 +557,10 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event)
continue
}

isDust := script.IsSubDustScript(out.PkScript)
outputSwept := txSwept
if !outputSwept {
outputSwept = script.IsSubDustScript(out.PkScript)
}

newVtxos = append(newVtxos, domain.Vtxo{
Outpoint: domain.Outpoint{
Expand All @@ -565,7 +577,7 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event)
// mark the vtxo as "swept" if it is below dust limit to prevent it from being spent again in a future offchain tx
// the only way to spend a swept vtxo is by collecting enough dust to cover the minSettlementVtxoAmount and then settle.
// because sub-dust vtxos are using OP_RETURN output script, they can't be unilaterally exited.
Swept: isDust,
Swept: outputSwept,
Assets: assets[uint32(outIndex)],
})
}
Expand Down
Loading
Loading