From 0b841ec686c26a048708105792b8c10337d40a4f Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 23 Sep 2016 15:15:22 -0700 Subject: [PATCH] channeldb: store optional invoice fields as variable length byte arrays This commit modifies the on-disk storage of invoices to stop the optional fields (memo+receipt) on-disk as variable length byte arrays. This change saves space as the optional fields now only take up as much space as is strictly needed, rather than always being padded out to max size (1KB). --- channeldb/invoice_test.go | 8 ++++---- channeldb/invoices.go | 26 ++++++++++++++++++++------ rpcserver.go | 4 ++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index 9398668b9..7f4338bb6 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -25,8 +25,8 @@ func randInvoice(value btcutil.Amount) (*Invoice, error) { Value: value, }, } - copy(i.Memo[:], []byte("memo")) - copy(i.Receipt[:], []byte("recipt")) + i.Memo = []byte("memo") + i.Receipt = []byte("recipt") return i, nil } @@ -43,8 +43,8 @@ func TestInvoiceWorkflow(t *testing.T) { fakeInvoice := &Invoice{ CreationDate: time.Now(), } - copy(fakeInvoice.Memo[:], []byte("memo")) - copy(fakeInvoice.Receipt[:], []byte("recipt")) + fakeInvoice.Memo = []byte("memo") + fakeInvoice.Receipt = []byte("recipt") copy(fakeInvoice.Terms.PaymentPreimage[:], rev[:]) fakeInvoice.Terms.Value = btcutil.Amount(10000) diff --git a/channeldb/invoices.go b/channeldb/invoices.go index d27ca23f7..d5febac48 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -2,6 +2,7 @@ package channeldb import ( "bytes" + "fmt" "io" "time" @@ -77,13 +78,13 @@ type Invoice struct { // Memo is an optional memo to be stored along side an invoice. The // memo may contain further details pertaining to the invoice itself, // or any other message which fits within the size constraints. - Memo [MaxMemoSize]byte + Memo []byte // Receipt is an optional field dedicated for storing a // cryptographically binding receipt of payment. // // TODO(roasbeef): document scheme. - Receipt [MaxReceiptSize]byte + Receipt []byte // CreationDate is the exact time the invoice was created. CreationDate time.Time @@ -102,6 +103,16 @@ type Invoice struct { // insertion will be aborted and rejected due to the strict policy banning any // duplicate payment hashes. func (d *DB) AddInvoice(i *Invoice) error { + if len(i.Memo) > MaxMemoSize { + return fmt.Errorf("max length a memo is %v, and invoice "+ + "of length %v was provided", MaxMemoSize, len(i.Memo)) + } + if len(i.Receipt) > MaxReceiptSize { + return fmt.Errorf("max length a receipt is %v, and invoice "+ + "of length %v was provided", MaxReceiptSize, + len(i.Receipt)) + } + return d.store.Update(func(tx *bolt.Tx) error { invoices, err := tx.CreateBucketIfNotExists(invoiceBucket) if err != nil { @@ -283,10 +294,10 @@ func putInvoice(invoices *bolt.Bucket, invoiceIndex *bolt.Bucket, } func serializeInvoice(w io.Writer, i *Invoice) error { - if _, err := w.Write(i.Memo[:]); err != nil { + if err := wire.WriteVarBytes(w, 0, i.Memo[:]); err != nil { return err } - if _, err := w.Write(i.Receipt[:]); err != nil { + if err := wire.WriteVarBytes(w, 0, i.Receipt[:]); err != nil { return err } @@ -331,13 +342,16 @@ func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (*Invoice, error) { } func deserializeInvoice(r io.Reader) (*Invoice, error) { + var err error invoice := &Invoice{} // TODO(roasbeef): use read full everywhere - if _, err := io.ReadFull(r, invoice.Memo[:]); err != nil { + invoice.Memo, err = wire.ReadVarBytes(r, 0, MaxMemoSize, "") + if err != nil { return nil, err } - if _, err := io.ReadFull(r, invoice.Receipt[:]); err != nil { + invoice.Receipt, err = wire.ReadVarBytes(r, 0, MaxReceiptSize, "") + if err != nil { return nil, err } diff --git a/rpcserver.go b/rpcserver.go index 7c410567b..304022ece 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -613,12 +613,12 @@ func (r *rpcServer) AddInvoice(ctx context.Context, i := &channeldb.Invoice{ CreationDate: time.Now(), + Memo: []byte(invoice.Memo), + Receipt: invoice.Receipt, Terms: channeldb.ContractTerm{ Value: btcutil.Amount(invoice.Value), }, } - copy(i.Memo[:], invoice.Memo) - copy(i.Receipt[:], invoice.Receipt) copy(i.Terms.PaymentPreimage[:], preImage) if err := r.server.invoices.AddInvoice(i); err != nil {