Skip to content

Commit

Permalink
Postage BatchStore and BatchService (#1070)
Browse files Browse the repository at this point in the history
Co-authored-by: zelig <viktor.tron@gmail.com>
  • Loading branch information
2 people authored and acud committed Jan 15, 2021
1 parent 8bd4df9 commit 7ac2189
Show file tree
Hide file tree
Showing 23 changed files with 1,101 additions and 127 deletions.
43 changes: 43 additions & 0 deletions pkg/postage/batch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package postage

import (
"encoding/binary"
"math/big"
)

// Batch represents a postage batch, a payment on the blockchain.
type Batch struct {
ID []byte // batch ID
Value *big.Int // overall balance of the batch
Start uint64 // block number the batch was created
Owner []byte // owner's ethereum address
Depth uint8 // batch depth, i.e., size = 2^{depth}
}

// MarshalBinary implements BinaryMarshaller. It will attempt to serialize the
// postage batch to a byte slice.
func (b *Batch) MarshalBinary() ([]byte, error) {
out := make([]byte, 93)
copy(out, b.ID)
value := b.Value.Bytes()
copy(out[64-len(value):], value)
binary.BigEndian.PutUint64(out[64:72], b.Start)
copy(out[72:], b.Owner)
out[92] = b.Depth
return out, nil
}

// UnmarshalBinary implements BinaryUnmarshaller. It will attempt deserialize
// the given byte slice into the batch.
func (b *Batch) UnmarshalBinary(buf []byte) error {
b.ID = buf[:32]
b.Value = big.NewInt(0).SetBytes(buf[32:64])
b.Start = binary.BigEndian.Uint64(buf[64:72])
b.Owner = buf[72:92]
b.Depth = buf[92]
return nil
}
46 changes: 46 additions & 0 deletions pkg/postage/batch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package postage_test

import (
"bytes"
"testing"

"github.com/ethersphere/bee/pkg/postage"
postagetesting "github.com/ethersphere/bee/pkg/postage/testing"
)

// TestBatchMarshalling tests the idempotence of binary marshal/unmarshal for a
// Batch.
func TestBatchMarshalling(t *testing.T) {
a := postagetesting.MustNewBatch()

buf, err := a.MarshalBinary()
if err != nil {
t.Fatal(err)
}
if len(buf) != 93 {
t.Fatalf("invalid length for serialised batch. expected 93, got %d", len(buf))
}
b := &postage.Batch{}
if err := b.UnmarshalBinary(buf); err != nil {
t.Fatalf("unexpected error unmarshalling batch: %v", err)
}
if !bytes.Equal(b.ID, a.ID) {
t.Fatalf("id mismatch, expected %x, got %x", a.ID, b.ID)
}
if !bytes.Equal(b.Owner, a.Owner) {
t.Fatalf("owner mismatch, expected %x, got %x", a.Owner, b.Owner)
}
if a.Value.Uint64() != b.Value.Uint64() {
t.Fatalf("value mismatch, expected %d, got %d", a.Value.Uint64(), b.Value.Uint64())
}
if a.Start != b.Start {
t.Fatalf("start mismatch, expected %d, got %d", a.Start, b.Start)
}
if a.Depth != b.Depth {
t.Fatalf("depth mismatch, expected %d, got %d", a.Depth, b.Depth)
}
}
107 changes: 107 additions & 0 deletions pkg/postage/batchservice/batchservice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package batchservice

import (
"encoding/hex"
"fmt"
"math/big"

"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/postage"
)

type batchService struct {
cs *postage.ChainState
storer postage.Storer
logger logging.Logger
}

// New will create a new BatchService.
func New(storer postage.Storer, logger logging.Logger) (postage.EventUpdater, error) {
b := &batchService{
storer: storer,
logger: logger,
}

cs, err := storer.GetChainState()
if err != nil {
return nil, fmt.Errorf("get chain state: %w", err)
}
b.cs = cs

return b, nil
}

// Create will create a new batch with the given ID, owner value and depth and
// stores it in the BatchStore.
func (svc *batchService) Create(id, owner []byte, value *big.Int, depth uint8) error {
b := &postage.Batch{
ID: id,
Owner: owner,
Value: value,
Start: svc.cs.Block,
Depth: depth,
}

err := svc.storer.Put(b)
if err != nil {
return fmt.Errorf("put: %w", err)
}

svc.logger.Debugf("created batch id %s", hex.EncodeToString(b.ID))
return nil
}

// TopUp implements the EventUpdater interface. It tops ups a batch with the
// given ID with the given amount.
func (svc *batchService) TopUp(id []byte, amount *big.Int) error {
b, err := svc.storer.Get(id)
if err != nil {
return fmt.Errorf("get: %w", err)
}

b.Value.Add(b.Value, amount)

err = svc.storer.Put(b)
if err != nil {
return fmt.Errorf("put: %w", err)
}

svc.logger.Debugf("topped up batch id %s with %v", hex.EncodeToString(b.ID), b.Value)
return nil
}

// UpdateDepth implements the EventUpdater inteface. It sets the new depth of a
// batch with the given ID.
func (svc *batchService) UpdateDepth(id []byte, depth uint8) error {
b, err := svc.storer.Get(id)
if err != nil {
return fmt.Errorf("get: %w", err)
}

b.Depth = depth

err = svc.storer.Put(b)
if err != nil {
return fmt.Errorf("put: %w", err)
}

svc.logger.Debugf("updated depth of batch id %s to %d", hex.EncodeToString(b.ID), b.Depth)
return nil
}

// UpdatePrice implements the EventUpdater interface. It sets the current
// price from the chain in the service chain state.
func (svc *batchService) UpdatePrice(price *big.Int) error {
svc.cs.Price = price

if err := svc.storer.PutChainState(svc.cs); err != nil {
return fmt.Errorf("put chain state: %w", err)
}

svc.logger.Debugf("updated chain price to %s", svc.cs.Price)
return nil
}
Loading

0 comments on commit 7ac2189

Please sign in to comment.