Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

soroban-rpc: Enforce atomicity within jsonrpc request batches #28

Open
paulbellamy opened this issue Apr 27, 2023 · 0 comments
Open

soroban-rpc: Enforce atomicity within jsonrpc request batches #28

paulbellamy opened this issue Apr 27, 2023 · 0 comments

Comments

@paulbellamy
Copy link
Contributor

What problem does your feature solve?

See discussion in #48

Currently the jsonrpc server provides support for request batching automatically. But, those requests are all processed in parallel with no atomicity guarantees between them. So, one response might be as of ledger x, and another could be as of ledger x+1.

What would you like to see?

We should use a single database transaction for a batch.

This means we need to:

  • Change the jsonrpc server to so that we can detect batches instead of having them handled automatically (I assume, check the docs).
  • Refactor the database transaction system so we can use a transaction for a whole batch. In the past I've done this with something roughly like:
type DB interface {
  // Standard db methods and stuff
  Exec(ctx context.Context, query string, ...args interface{}) error    
  io.Closer
  // etc

  // Execute some code in a transaction
  Transaction(fn func(db DB) error) error
}

func (d *sqliteDB) Transaction(fn func(db DB) error) error {
  tx := txWrapper{d.BeginTx()}
  err := fn(tx)
  if err == nil {
    tx.Commit()
  } else {
    tx.Rollback()
  }
  return err
}

// txWrapper implements the DB interface
type txWrapper struct {
  *Transaction
}

// Standard db methods implemented on txWrapper
// func (tx *txWrapper) Exec(ctx context.Context, query string, ...args interface{}) error    
// etc

func (tx *txWrapper) Transaction(fn (d DB) error) error {
  // We are already in a transaction, no-op.
  return fn(tx)
}

func main() {
  conn := sqlite.Open(...)
  conn.Transaction(func(db DB) error {
    // This code now is in a transaction, but it doesn't know that.
    return db.Transaction(func(db DB) error {
      // It can nest transactions, but this will still only open a single transaction with the database.
    })
  })
}

What alternatives are there?

Don't do it, and tell users there is not atomicity within batches.

@stellarsaur stellarsaur transferred this issue from stellar/stellar-cli Feb 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Backlog
Development

No branches or pull requests

1 participant