Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mybee
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
mybee
Commits
81988b16
Unverified
Commit
81988b16
authored
Aug 23, 2021
by
aloknerurkar
Committed by
GitHub
Aug 23, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(debugapi, postage): topup batch handling (#2401)
parent
136d9f2c
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
651 additions
and
61 deletions
+651
-61
SwarmDebug.yaml
openapi/SwarmDebug.yaml
+37
-0
postage.go
pkg/debugapi/postage.go
+60
-0
postage_test.go
pkg/debugapi/postage_test.go
+118
-0
router.go
pkg/debugapi/router.go
+6
-0
devnode.go
pkg/node/devnode.go
+46
-22
node.go
pkg/node/node.go
+1
-0
batchservice.go
pkg/postage/batchservice/batchservice.go
+9
-3
batchservice_test.go
pkg/postage/batchservice/batchservice_test.go
+76
-17
interface.go
pkg/postage/interface.go
+3
-2
service.go
pkg/postage/mock/service.go
+3
-1
contract.go
pkg/postage/postagecontract/contract.go
+87
-10
contract_test.go
pkg/postage/postagecontract/contract_test.go
+160
-0
export_test.go
pkg/postage/postagecontract/export_test.go
+1
-0
contract.go
pkg/postage/postagecontract/mock/contract.go
+11
-0
service.go
pkg/postage/service.go
+20
-3
service_test.go
pkg/postage/service_test.go
+13
-3
No files found.
openapi/SwarmDebug.yaml
View file @
81988b16
...
@@ -871,3 +871,40 @@ paths:
...
@@ -871,3 +871,40 @@ paths:
$ref
:
"
SwarmCommon.yaml#/components/responses/500"
$ref
:
"
SwarmCommon.yaml#/components/responses/500"
default
:
default
:
description
:
Default response
description
:
Default response
"
/stamps/topup/{id}/{amount}"
:
patch
:
summary
:
Top up an existing postage batch.
description
:
Be aware, this endpoint creates on-chain transactions and transfers BZZ from the node's Ethereum account and hence directly manipulates the wallet balance!
tags
:
-
Postage Stamps
parameters
:
-
in
:
path
name
:
id
schema
:
$ref
:
"
SwarmCommon.yaml#/components/schemas/BatchID"
required
:
true
description
:
Batch ID to top up
-
in
:
path
name
:
amount
schema
:
type
:
integer
required
:
true
description
:
Amount of BZZ per chunk to top up to an existing postage batch.
responses
:
"
202"
:
description
:
Returns the postage batch ID that was topped up
content
:
application/json
:
schema
:
$ref
:
"
SwarmCommon.yaml#/components/schemas/BatchIDResponse"
"
400"
:
$ref
:
"
SwarmCommon.yaml#/components/responses/400"
"
429"
:
$ref
:
"
SwarmCommon.yaml#/components/responses/429"
"
402"
:
$ref
:
"
SwarmCommon.yaml#/components/responses/402"
"
500"
:
$ref
:
"
SwarmCommon.yaml#/components/responses/500"
default
:
description
:
Default response
pkg/debugapi/postage.go
View file @
81988b16
...
@@ -321,3 +321,63 @@ func (s *Service) estimateBatchTTL(id []byte) (int64, error) {
...
@@ -321,3 +321,63 @@ func (s *Service) estimateBatchTTL(id []byte) (int64, error) {
return
ttl
.
Int64
(),
nil
return
ttl
.
Int64
(),
nil
}
}
func
(
s
*
Service
)
postageTopUpHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
idStr
:=
mux
.
Vars
(
r
)[
"id"
]
if
idStr
==
""
||
len
(
idStr
)
!=
64
{
s
.
logger
.
Error
(
"topup batch: invalid batchID"
)
jsonhttp
.
BadRequest
(
w
,
"invalid batchID"
)
return
}
id
,
err
:=
hex
.
DecodeString
(
idStr
)
if
err
!=
nil
{
s
.
logger
.
Debugf
(
"topup batch: invalid batchID: %v"
,
err
)
s
.
logger
.
Error
(
"topup batch: invalid batchID"
)
jsonhttp
.
BadRequest
(
w
,
"invalid batchID"
)
return
}
amount
,
ok
:=
big
.
NewInt
(
0
)
.
SetString
(
mux
.
Vars
(
r
)[
"amount"
],
10
)
if
!
ok
{
s
.
logger
.
Error
(
"topup batch: invalid amount"
)
jsonhttp
.
BadRequest
(
w
,
"invalid postage amount"
)
return
}
ctx
:=
r
.
Context
()
if
price
,
ok
:=
r
.
Header
[
gasPriceHeader
];
ok
{
p
,
ok
:=
big
.
NewInt
(
0
)
.
SetString
(
price
[
0
],
10
)
if
!
ok
{
s
.
logger
.
Error
(
"topup batch: bad gas price"
)
jsonhttp
.
BadRequest
(
w
,
errBadGasPrice
)
return
}
ctx
=
sctx
.
SetGasPrice
(
ctx
,
p
)
}
if
!
s
.
postageCreateSem
.
TryAcquire
(
1
)
{
s
.
logger
.
Debug
(
"topup batch: simultaneous on-chain operations not supported"
)
s
.
logger
.
Error
(
"topup batch: simultaneous on-chain operations not supported"
)
jsonhttp
.
TooManyRequests
(
w
,
"simultaneous on-chain operations not supported"
)
return
}
defer
s
.
postageCreateSem
.
Release
(
1
)
err
=
s
.
postageContract
.
TopUpBatch
(
ctx
,
id
,
amount
)
if
err
!=
nil
{
if
errors
.
Is
(
err
,
postagecontract
.
ErrInsufficientFunds
)
{
s
.
logger
.
Debugf
(
"topup batch: out of funds: %v"
,
err
)
s
.
logger
.
Error
(
"topup batch: out of funds"
)
jsonhttp
.
PaymentRequired
(
w
,
"out of funds"
)
return
}
s
.
logger
.
Debugf
(
"topup batch: failed to create: %v"
,
err
)
s
.
logger
.
Error
(
"topup batch: failed to create"
)
jsonhttp
.
InternalServerError
(
w
,
"cannot topup batch"
)
return
}
jsonhttp
.
Accepted
(
w
,
&
postageCreateResponse
{
BatchID
:
id
,
})
}
pkg/debugapi/postage_test.go
View file @
81988b16
...
@@ -5,6 +5,7 @@
...
@@ -5,6 +5,7 @@
package
debugapi_test
package
debugapi_test
import
(
import
(
"bytes"
"context"
"context"
"encoding/hex"
"encoding/hex"
"errors"
"errors"
...
@@ -368,3 +369,120 @@ func TestChainState(t *testing.T) {
...
@@ -368,3 +369,120 @@ func TestChainState(t *testing.T) {
)
)
})
})
}
}
func
TestPostageTopUpStamp
(
t
*
testing
.
T
)
{
topupAmount
:=
int64
(
1000
)
topupBatch
:=
func
(
id
string
,
amount
int64
)
string
{
return
fmt
.
Sprintf
(
"/stamps/topup/%s/%d"
,
id
,
amount
)
}
t
.
Run
(
"ok"
,
func
(
t
*
testing
.
T
)
{
contract
:=
contractMock
.
New
(
contractMock
.
WithTopUpBatchFunc
(
func
(
ctx
context
.
Context
,
id
[]
byte
,
ib
*
big
.
Int
)
error
{
if
!
bytes
.
Equal
(
id
,
batchOk
)
{
return
errors
.
New
(
"incorrect batch ID in call"
)
}
if
ib
.
Cmp
(
big
.
NewInt
(
topupAmount
))
!=
0
{
return
fmt
.
Errorf
(
"called with wrong topup amount. wanted %d, got %d"
,
topupAmount
,
ib
)
}
return
nil
}),
)
ts
:=
newTestServer
(
t
,
testServerOptions
{
PostageContract
:
contract
,
})
jsonhttptest
.
Request
(
t
,
ts
.
Client
,
http
.
MethodPatch
,
topupBatch
(
batchOkStr
,
topupAmount
),
http
.
StatusAccepted
,
jsonhttptest
.
WithExpectedJSONResponse
(
&
debugapi
.
PostageCreateResponse
{
BatchID
:
batchOk
,
}),
)
})
t
.
Run
(
"with-custom-gas"
,
func
(
t
*
testing
.
T
)
{
contract
:=
contractMock
.
New
(
contractMock
.
WithTopUpBatchFunc
(
func
(
ctx
context
.
Context
,
id
[]
byte
,
ib
*
big
.
Int
)
error
{
if
!
bytes
.
Equal
(
id
,
batchOk
)
{
return
errors
.
New
(
"incorrect batch ID in call"
)
}
if
ib
.
Cmp
(
big
.
NewInt
(
topupAmount
))
!=
0
{
return
fmt
.
Errorf
(
"called with wrong topup amount. wanted %d, got %d"
,
topupAmount
,
ib
)
}
if
sctx
.
GetGasPrice
(
ctx
)
.
Cmp
(
big
.
NewInt
(
10000
))
!=
0
{
return
fmt
.
Errorf
(
"called with wrong gas price. wanted %d, got %d"
,
10000
,
sctx
.
GetGasPrice
(
ctx
))
}
return
nil
}),
)
ts
:=
newTestServer
(
t
,
testServerOptions
{
PostageContract
:
contract
,
})
jsonhttptest
.
Request
(
t
,
ts
.
Client
,
http
.
MethodPatch
,
topupBatch
(
batchOkStr
,
topupAmount
),
http
.
StatusAccepted
,
jsonhttptest
.
WithRequestHeader
(
"Gas-Price"
,
"10000"
),
jsonhttptest
.
WithExpectedJSONResponse
(
&
debugapi
.
PostageCreateResponse
{
BatchID
:
batchOk
,
}),
)
})
t
.
Run
(
"with-error"
,
func
(
t
*
testing
.
T
)
{
contract
:=
contractMock
.
New
(
contractMock
.
WithTopUpBatchFunc
(
func
(
ctx
context
.
Context
,
id
[]
byte
,
ib
*
big
.
Int
)
error
{
return
errors
.
New
(
"err"
)
}),
)
ts
:=
newTestServer
(
t
,
testServerOptions
{
PostageContract
:
contract
,
})
jsonhttptest
.
Request
(
t
,
ts
.
Client
,
http
.
MethodPatch
,
topupBatch
(
batchOkStr
,
topupAmount
),
http
.
StatusInternalServerError
,
jsonhttptest
.
WithExpectedJSONResponse
(
&
jsonhttp
.
StatusResponse
{
Code
:
http
.
StatusInternalServerError
,
Message
:
"cannot topup batch"
,
}),
)
})
t
.
Run
(
"out-of-funds"
,
func
(
t
*
testing
.
T
)
{
contract
:=
contractMock
.
New
(
contractMock
.
WithTopUpBatchFunc
(
func
(
ctx
context
.
Context
,
id
[]
byte
,
ib
*
big
.
Int
)
error
{
return
postagecontract
.
ErrInsufficientFunds
}),
)
ts
:=
newTestServer
(
t
,
testServerOptions
{
PostageContract
:
contract
,
})
jsonhttptest
.
Request
(
t
,
ts
.
Client
,
http
.
MethodPatch
,
topupBatch
(
batchOkStr
,
topupAmount
),
http
.
StatusPaymentRequired
,
jsonhttptest
.
WithExpectedJSONResponse
(
&
jsonhttp
.
StatusResponse
{
Code
:
http
.
StatusPaymentRequired
,
Message
:
"out of funds"
,
}),
)
})
t
.
Run
(
"invalid batch id"
,
func
(
t
*
testing
.
T
)
{
ts
:=
newTestServer
(
t
,
testServerOptions
{})
jsonhttptest
.
Request
(
t
,
ts
.
Client
,
http
.
MethodPatch
,
"/stamps/topup/abcd/2"
,
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
&
jsonhttp
.
StatusResponse
{
Code
:
http
.
StatusBadRequest
,
Message
:
"invalid batchID"
,
}),
)
})
t
.
Run
(
"invalid amount"
,
func
(
t
*
testing
.
T
)
{
ts
:=
newTestServer
(
t
,
testServerOptions
{})
wrongURL
:=
fmt
.
Sprintf
(
"/stamps/topup/%s/amount"
,
batchOkStr
)
jsonhttptest
.
Request
(
t
,
ts
.
Client
,
http
.
MethodPatch
,
wrongURL
,
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
&
jsonhttp
.
StatusResponse
{
Code
:
http
.
StatusBadRequest
,
Message
:
"invalid postage amount"
,
}),
)
})
}
pkg/debugapi/router.go
View file @
81988b16
...
@@ -210,6 +210,12 @@ func (s *Service) newRouter() *mux.Router {
...
@@ -210,6 +210,12 @@ func (s *Service) newRouter() *mux.Router {
})),
})),
)
)
router
.
Handle
(
"/stamps/topup/{id}/{amount}"
,
web
.
ChainHandlers
(
web
.
FinalHandler
(
jsonhttp
.
MethodHandler
{
"PATCH"
:
http
.
HandlerFunc
(
s
.
postageTopUpHandler
),
})),
)
return
router
return
router
}
}
...
...
pkg/node/devnode.go
View file @
81988b16
...
@@ -200,28 +200,52 @@ func NewDevBee(logger logging.Logger, o *DevOptions) (b *DevBee, err error) {
...
@@ -200,28 +200,52 @@ func NewDevBee(logger logging.Logger, o *DevOptions) (b *DevBee, err error) {
}
}
post
:=
mockPost
.
New
()
post
:=
mockPost
.
New
()
postageContract
:=
mockPostContract
.
New
(
mockPostContract
.
WithCreateBatchFunc
(
postageContract
:=
mockPostContract
.
New
(
func
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
{
mockPostContract
.
WithCreateBatchFunc
(
id
:=
postagetesting
.
MustNewID
()
func
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
{
b
:=
&
postage
.
Batch
{
id
:=
postagetesting
.
MustNewID
()
ID
:
id
,
b
:=
&
postage
.
Batch
{
Owner
:
overlayEthAddress
.
Bytes
(),
ID
:
id
,
Value
:
big
.
NewInt
(
0
),
Owner
:
overlayEthAddress
.
Bytes
(),
Depth
:
depth
,
Value
:
big
.
NewInt
(
0
),
Immutable
:
immutable
,
Depth
:
depth
,
}
Immutable
:
immutable
,
}
err
:=
batchStore
.
Put
(
b
,
initialBalance
,
depth
)
if
err
!=
nil
{
totalAmount
:=
big
.
NewInt
(
0
)
.
Mul
(
initialBalance
,
big
.
NewInt
(
int64
(
1
<<
depth
)))
return
nil
,
err
}
err
:=
batchStore
.
Put
(
b
,
totalAmount
,
depth
)
if
err
!=
nil
{
stampIssuer
:=
postage
.
NewStampIssuer
(
label
,
string
(
overlayEthAddress
.
Bytes
()),
id
,
initialBalance
,
depth
,
0
,
0
,
immutable
)
return
nil
,
err
post
.
Add
(
stampIssuer
)
}
return
id
,
nil
stampIssuer
:=
postage
.
NewStampIssuer
(
label
,
string
(
overlayEthAddress
.
Bytes
()),
id
,
totalAmount
,
depth
,
0
,
0
,
immutable
)
},
post
.
Add
(
stampIssuer
)
))
return
id
,
nil
},
),
mockPostContract
.
WithTopUpBatchFunc
(
func
(
ctx
context
.
Context
,
batchID
[]
byte
,
topupAmount
*
big
.
Int
)
error
{
batch
,
err
:=
batchStore
.
Get
(
batchID
)
if
err
!=
nil
{
return
err
}
totalAmount
:=
big
.
NewInt
(
0
)
.
Mul
(
topupAmount
,
big
.
NewInt
(
int64
(
1
<<
batch
.
Depth
)))
newBalance
:=
big
.
NewInt
(
0
)
.
Add
(
totalAmount
,
batch
.
Value
)
err
=
batchStore
.
Put
(
batch
,
newBalance
,
batch
.
Depth
)
if
err
!=
nil
{
return
err
}
post
.
HandleTopUp
(
batch
.
ID
,
newBalance
)
return
nil
},
),
)
feedFactory
:=
factory
.
New
(
storer
)
feedFactory
:=
factory
.
New
(
storer
)
...
...
pkg/node/node.go
View file @
81988b16
...
@@ -464,6 +464,7 @@ func NewBee(addr string, publicKey *ecdsa.PublicKey, signer crypto.Signer, netwo
...
@@ -464,6 +464,7 @@ func NewBee(addr string, publicKey *ecdsa.PublicKey, signer crypto.Signer, netwo
erc20Address
,
erc20Address
,
transactionService
,
transactionService
,
post
,
post
,
batchStore
,
)
)
if
natManager
:=
p2ps
.
NATManager
();
natManager
!=
nil
{
if
natManager
:=
p2ps
.
NATManager
();
natManager
!=
nil
{
...
...
pkg/postage/batchservice/batchservice.go
View file @
81988b16
...
@@ -29,7 +29,7 @@ type batchService struct {
...
@@ -29,7 +29,7 @@ type batchService struct {
logger
logging
.
Logger
logger
logging
.
Logger
listener
postage
.
Listener
listener
postage
.
Listener
owner
[]
byte
owner
[]
byte
batchListener
postage
.
Batch
Creation
Listener
batchListener
postage
.
Batch
Event
Listener
checksum
hash
.
Hash
// checksum hasher
checksum
hash
.
Hash
// checksum hasher
resync
bool
resync
bool
...
@@ -46,7 +46,7 @@ func New(
...
@@ -46,7 +46,7 @@ func New(
logger
logging
.
Logger
,
logger
logging
.
Logger
,
listener
postage
.
Listener
,
listener
postage
.
Listener
,
owner
[]
byte
,
owner
[]
byte
,
batchListener
postage
.
Batch
Creation
Listener
,
batchListener
postage
.
Batch
Event
Listener
,
checksumFunc
func
()
hash
.
Hash
,
checksumFunc
func
()
hash
.
Hash
,
resync
bool
,
resync
bool
,
)
(
Interface
,
error
)
{
)
(
Interface
,
error
)
{
...
@@ -110,8 +110,9 @@ func (svc *batchService) Create(id, owner []byte, normalisedBalance *big.Int, de
...
@@ -110,8 +110,9 @@ func (svc *batchService) Create(id, owner []byte, normalisedBalance *big.Int, de
}
}
if
bytes
.
Equal
(
svc
.
owner
,
owner
)
&&
svc
.
batchListener
!=
nil
{
if
bytes
.
Equal
(
svc
.
owner
,
owner
)
&&
svc
.
batchListener
!=
nil
{
svc
.
batchListener
.
Handle
(
b
)
svc
.
batchListener
.
Handle
Create
(
b
)
}
}
cs
,
err
:=
svc
.
updateChecksum
(
txHash
)
cs
,
err
:=
svc
.
updateChecksum
(
txHash
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"update checksum: %w"
,
err
)
return
fmt
.
Errorf
(
"update checksum: %w"
,
err
)
...
@@ -133,6 +134,11 @@ func (svc *batchService) TopUp(id []byte, normalisedBalance *big.Int, txHash []b
...
@@ -133,6 +134,11 @@ func (svc *batchService) TopUp(id []byte, normalisedBalance *big.Int, txHash []b
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"put: %w"
,
err
)
return
fmt
.
Errorf
(
"put: %w"
,
err
)
}
}
if
bytes
.
Equal
(
svc
.
owner
,
b
.
Owner
)
&&
svc
.
batchListener
!=
nil
{
svc
.
batchListener
.
HandleTopUp
(
id
,
normalisedBalance
)
}
cs
,
err
:=
svc
.
updateChecksum
(
txHash
)
cs
,
err
:=
svc
.
updateChecksum
(
txHash
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"update checksum: %w"
,
err
)
return
fmt
.
Errorf
(
"update checksum: %w"
,
err
)
...
...
pkg/postage/batchservice/batchservice_test.go
View file @
81988b16
...
@@ -38,12 +38,17 @@ func newMockListener() *mockListener {
...
@@ -38,12 +38,17 @@ func newMockListener() *mockListener {
return
&
mockListener
{}
return
&
mockListener
{}
}
}
type
mockBatchCreationHandler
struct
{
type
mockBatchListener
struct
{
count
int
createCount
int
topupCount
int
}
}
func
(
m
*
mockBatchCreationHandler
)
Handle
(
b
*
postage
.
Batch
)
{
func
(
m
*
mockBatchListener
)
HandleCreate
(
b
*
postage
.
Batch
)
{
m
.
count
++
m
.
createCount
++
}
func
(
m
*
mockBatchListener
)
HandleTopUp
(
_
[]
byte
,
_
*
big
.
Int
)
{
m
.
topupCount
++
}
}
func
TestBatchServiceCreate
(
t
*
testing
.
T
)
{
func
TestBatchServiceCreate
(
t
*
testing
.
T
)
{
...
@@ -51,7 +56,7 @@ func TestBatchServiceCreate(t *testing.T) {
...
@@ -51,7 +56,7 @@ func TestBatchServiceCreate(t *testing.T) {
t
.
Run
(
"expect put create put error"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"expect put create put error"
,
func
(
t
*
testing
.
T
)
{
testBatch
:=
postagetesting
.
MustNewBatch
()
testBatch
:=
postagetesting
.
MustNewBatch
()
testBatchListener
:=
&
mockBatch
CreationHandl
er
{}
testBatchListener
:=
&
mockBatch
Listen
er
{}
svc
,
_
,
_
:=
newTestStoreAndServiceWithListener
(
svc
,
_
,
_
:=
newTestStoreAndServiceWithListener
(
t
,
t
,
testBatch
.
Owner
,
testBatch
.
Owner
,
...
@@ -71,8 +76,8 @@ func TestBatchServiceCreate(t *testing.T) {
...
@@ -71,8 +76,8 @@ func TestBatchServiceCreate(t *testing.T) {
);
err
==
nil
{
);
err
==
nil
{
t
.
Fatalf
(
"expected error"
)
t
.
Fatalf
(
"expected error"
)
}
}
if
testBatchListener
.
count
!=
0
{
if
testBatchListener
.
c
reateC
ount
!=
0
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
0
,
testBatchListener
.
count
)
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
0
,
testBatchListener
.
c
reateC
ount
)
}
}
})
})
...
@@ -107,7 +112,7 @@ func TestBatchServiceCreate(t *testing.T) {
...
@@ -107,7 +112,7 @@ func TestBatchServiceCreate(t *testing.T) {
t
.
Run
(
"passes"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"passes"
,
func
(
t
*
testing
.
T
)
{
testBatch
:=
postagetesting
.
MustNewBatch
()
testBatch
:=
postagetesting
.
MustNewBatch
()
testBatchListener
:=
&
mockBatch
CreationHandl
er
{}
testBatchListener
:=
&
mockBatch
Listen
er
{}
svc
,
batchStore
,
_
:=
newTestStoreAndServiceWithListener
(
svc
,
batchStore
,
_
:=
newTestStoreAndServiceWithListener
(
t
,
t
,
testBatch
.
Owner
,
testBatch
.
Owner
,
...
@@ -126,8 +131,8 @@ func TestBatchServiceCreate(t *testing.T) {
...
@@ -126,8 +131,8 @@ func TestBatchServiceCreate(t *testing.T) {
);
err
!=
nil
{
);
err
!=
nil
{
t
.
Fatalf
(
"got error %v"
,
err
)
t
.
Fatalf
(
"got error %v"
,
err
)
}
}
if
testBatchListener
.
count
!=
1
{
if
testBatchListener
.
c
reateC
ount
!=
1
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
1
,
testBatchListener
.
count
)
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
1
,
testBatchListener
.
c
reateC
ount
)
}
}
validateBatch
(
t
,
testBatch
,
batchStore
)
validateBatch
(
t
,
testBatch
,
batchStore
)
...
@@ -135,7 +140,7 @@ func TestBatchServiceCreate(t *testing.T) {
...
@@ -135,7 +140,7 @@ func TestBatchServiceCreate(t *testing.T) {
t
.
Run
(
"passes without recovery"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"passes without recovery"
,
func
(
t
*
testing
.
T
)
{
testBatch
:=
postagetesting
.
MustNewBatch
()
testBatch
:=
postagetesting
.
MustNewBatch
()
testBatchListener
:=
&
mockBatch
CreationHandl
er
{}
testBatchListener
:=
&
mockBatch
Listen
er
{}
// create a owner different from the batch owner
// create a owner different from the batch owner
owner
:=
make
([]
byte
,
32
)
owner
:=
make
([]
byte
,
32
)
rand
.
Read
(
owner
)
rand
.
Read
(
owner
)
...
@@ -158,8 +163,8 @@ func TestBatchServiceCreate(t *testing.T) {
...
@@ -158,8 +163,8 @@ func TestBatchServiceCreate(t *testing.T) {
);
err
!=
nil
{
);
err
!=
nil
{
t
.
Fatalf
(
"got error %v"
,
err
)
t
.
Fatalf
(
"got error %v"
,
err
)
}
}
if
testBatchListener
.
count
!=
0
{
if
testBatchListener
.
c
reateC
ount
!=
0
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
1
,
testBatchListener
.
c
ount
)
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
0
,
testBatchListener
.
createC
ount
)
}
}
validateBatch
(
t
,
testBatch
,
batchStore
)
validateBatch
(
t
,
testBatch
,
batchStore
)
...
@@ -171,19 +176,28 @@ func TestBatchServiceTopUp(t *testing.T) {
...
@@ -171,19 +176,28 @@ func TestBatchServiceTopUp(t *testing.T) {
testNormalisedBalance
:=
big
.
NewInt
(
2000000000000
)
testNormalisedBalance
:=
big
.
NewInt
(
2000000000000
)
t
.
Run
(
"expect get error"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"expect get error"
,
func
(
t
*
testing
.
T
)
{
svc
,
_
,
_
:=
newTestStoreAndService
(
testBatchListener
:=
&
mockBatchListener
{}
svc
,
_
,
_
:=
newTestStoreAndServiceWithListener
(
t
,
t
,
testBatch
.
Owner
,
testBatchListener
,
mock
.
WithGetErr
(
errTest
,
0
),
mock
.
WithGetErr
(
errTest
,
0
),
)
)
if
err
:=
svc
.
TopUp
(
testBatch
.
ID
,
testNormalisedBalance
,
testTxHash
);
err
==
nil
{
if
err
:=
svc
.
TopUp
(
testBatch
.
ID
,
testNormalisedBalance
,
testTxHash
);
err
==
nil
{
t
.
Fatal
(
"expected error"
)
t
.
Fatal
(
"expected error"
)
}
}
if
testBatchListener
.
topupCount
!=
0
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
0
,
testBatchListener
.
topupCount
)
}
})
})
t
.
Run
(
"expect put error"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"expect put error"
,
func
(
t
*
testing
.
T
)
{
svc
,
batchStore
,
_
:=
newTestStoreAndService
(
testBatchListener
:=
&
mockBatchListener
{}
svc
,
batchStore
,
_
:=
newTestStoreAndServiceWithListener
(
t
,
t
,
testBatch
.
Owner
,
testBatchListener
,
mock
.
WithPutErr
(
errTest
,
1
),
mock
.
WithPutErr
(
errTest
,
1
),
)
)
putBatch
(
t
,
batchStore
,
testBatch
)
putBatch
(
t
,
batchStore
,
testBatch
)
...
@@ -191,10 +205,18 @@ func TestBatchServiceTopUp(t *testing.T) {
...
@@ -191,10 +205,18 @@ func TestBatchServiceTopUp(t *testing.T) {
if
err
:=
svc
.
TopUp
(
testBatch
.
ID
,
testNormalisedBalance
,
testTxHash
);
err
==
nil
{
if
err
:=
svc
.
TopUp
(
testBatch
.
ID
,
testNormalisedBalance
,
testTxHash
);
err
==
nil
{
t
.
Fatal
(
"expected error"
)
t
.
Fatal
(
"expected error"
)
}
}
if
testBatchListener
.
topupCount
!=
0
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
0
,
testBatchListener
.
topupCount
)
}
})
})
t
.
Run
(
"passes"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"passes"
,
func
(
t
*
testing
.
T
)
{
svc
,
batchStore
,
_
:=
newTestStoreAndService
(
t
)
testBatchListener
:=
&
mockBatchListener
{}
svc
,
batchStore
,
_
:=
newTestStoreAndServiceWithListener
(
t
,
testBatch
.
Owner
,
testBatchListener
,
)
putBatch
(
t
,
batchStore
,
testBatch
)
putBatch
(
t
,
batchStore
,
testBatch
)
want
:=
testNormalisedBalance
want
:=
testNormalisedBalance
...
@@ -211,6 +233,43 @@ func TestBatchServiceTopUp(t *testing.T) {
...
@@ -211,6 +233,43 @@ func TestBatchServiceTopUp(t *testing.T) {
if
got
.
Value
.
Cmp
(
want
)
!=
0
{
if
got
.
Value
.
Cmp
(
want
)
!=
0
{
t
.
Fatalf
(
"topped up amount: got %v, want %v"
,
got
.
Value
,
want
)
t
.
Fatalf
(
"topped up amount: got %v, want %v"
,
got
.
Value
,
want
)
}
}
if
testBatchListener
.
topupCount
!=
1
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
1
,
testBatchListener
.
topupCount
)
}
})
// if a batch with a different owner is topped up we should not see any event fired in the
// batch service
t
.
Run
(
"passes without BatchEventListener update"
,
func
(
t
*
testing
.
T
)
{
testBatchListener
:=
&
mockBatchListener
{}
// create a owner different from the batch owner
owner
:=
make
([]
byte
,
32
)
rand
.
Read
(
owner
)
svc
,
batchStore
,
_
:=
newTestStoreAndServiceWithListener
(
t
,
owner
,
testBatchListener
,
)
putBatch
(
t
,
batchStore
,
testBatch
)
want
:=
testNormalisedBalance
if
err
:=
svc
.
TopUp
(
testBatch
.
ID
,
testNormalisedBalance
,
testTxHash
);
err
!=
nil
{
t
.
Fatalf
(
"top up: %v"
,
err
)
}
got
,
err
:=
batchStore
.
Get
(
testBatch
.
ID
)
if
err
!=
nil
{
t
.
Fatalf
(
"batch store get: %v"
,
err
)
}
if
got
.
Value
.
Cmp
(
want
)
!=
0
{
t
.
Fatalf
(
"topped up amount: got %v, want %v"
,
got
.
Value
,
want
)
}
if
testBatchListener
.
topupCount
!=
0
{
t
.
Fatalf
(
"unexpected batch listener count, exp %d found %d"
,
0
,
testBatchListener
.
topupCount
)
}
})
})
}
}
...
@@ -435,7 +494,7 @@ func TestChecksumResync(t *testing.T) {
...
@@ -435,7 +494,7 @@ func TestChecksumResync(t *testing.T) {
func
newTestStoreAndServiceWithListener
(
func
newTestStoreAndServiceWithListener
(
t
*
testing
.
T
,
t
*
testing
.
T
,
owner
[]
byte
,
owner
[]
byte
,
batchListener
postage
.
Batch
Creation
Listener
,
batchListener
postage
.
Batch
Event
Listener
,
opts
...
mock
.
Option
,
opts
...
mock
.
Option
,
)
(
postage
.
EventUpdater
,
*
mock
.
BatchStore
,
storage
.
StateStorer
)
{
)
(
postage
.
EventUpdater
,
*
mock
.
BatchStore
,
storage
.
StateStorer
)
{
t
.
Helper
()
t
.
Helper
()
...
...
pkg/postage/interface.go
View file @
81988b16
...
@@ -50,6 +50,7 @@ type Listener interface {
...
@@ -50,6 +50,7 @@ type Listener interface {
Listen
(
from
uint64
,
updater
EventUpdater
)
<-
chan
struct
{}
Listen
(
from
uint64
,
updater
EventUpdater
)
<-
chan
struct
{}
}
}
type
BatchCreationListener
interface
{
type
BatchEventListener
interface
{
Handle
(
*
Batch
)
HandleCreate
(
*
Batch
)
HandleTopUp
(
id
[]
byte
,
newBalance
*
big
.
Int
)
}
}
pkg/postage/mock/service.go
View file @
81988b16
...
@@ -88,7 +88,9 @@ func (m *mockPostage) IssuerUsable(_ *postage.StampIssuer) bool {
...
@@ -88,7 +88,9 @@ func (m *mockPostage) IssuerUsable(_ *postage.StampIssuer) bool {
return
true
return
true
}
}
func
(
m
*
mockPostage
)
Handle
(
_
*
postage
.
Batch
)
{}
func
(
m
*
mockPostage
)
HandleCreate
(
_
*
postage
.
Batch
)
{}
func
(
m
*
mockPostage
)
HandleTopUp
(
_
[]
byte
,
_
*
big
.
Int
)
{}
func
(
m
*
mockPostage
)
Close
()
error
{
func
(
m
*
mockPostage
)
Close
()
error
{
return
nil
return
nil
...
...
pkg/postage/postagecontract/contract.go
View file @
81988b16
...
@@ -28,14 +28,17 @@ var (
...
@@ -28,14 +28,17 @@ var (
postageStampABI
=
parseABI
(
postageabi
.
PostageStampABIv0_3_0
)
postageStampABI
=
parseABI
(
postageabi
.
PostageStampABIv0_3_0
)
erc20ABI
=
parseABI
(
sw3abi
.
ERC20ABIv0_3_1
)
erc20ABI
=
parseABI
(
sw3abi
.
ERC20ABIv0_3_1
)
batchCreatedTopic
=
postageStampABI
.
Events
[
"BatchCreated"
]
.
ID
batchCreatedTopic
=
postageStampABI
.
Events
[
"BatchCreated"
]
.
ID
batchTopUpTopic
=
postageStampABI
.
Events
[
"BatchTopUp"
]
.
ID
ErrBatchCreate
=
errors
.
New
(
"batch creation failed"
)
ErrBatchCreate
=
errors
.
New
(
"batch creation failed"
)
ErrInsufficientFunds
=
errors
.
New
(
"insufficient token balance"
)
ErrInsufficientFunds
=
errors
.
New
(
"insufficient token balance"
)
ErrInvalidDepth
=
errors
.
New
(
"invalid depth"
)
ErrInvalidDepth
=
errors
.
New
(
"invalid depth"
)
ErrBatchTopUp
=
errors
.
New
(
"batch topUp failed"
)
)
)
type
Interface
interface
{
type
Interface
interface
{
CreateBatch
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
CreateBatch
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
TopUpBatch
(
ctx
context
.
Context
,
batchID
[]
byte
,
topupBalance
*
big
.
Int
)
error
}
}
type
postageContract
struct
{
type
postageContract
struct
{
...
@@ -44,6 +47,7 @@ type postageContract struct {
...
@@ -44,6 +47,7 @@ type postageContract struct {
bzzTokenAddress
common
.
Address
bzzTokenAddress
common
.
Address
transactionService
transaction
.
Service
transactionService
transaction
.
Service
postageService
postage
.
Service
postageService
postage
.
Service
postageStorer
postage
.
Storer
}
}
func
New
(
func
New
(
...
@@ -52,6 +56,7 @@ func New(
...
@@ -52,6 +56,7 @@ func New(
bzzTokenAddress
common
.
Address
,
bzzTokenAddress
common
.
Address
,
transactionService
transaction
.
Service
,
transactionService
transaction
.
Service
,
postageService
postage
.
Service
,
postageService
postage
.
Service
,
postageStorer
postage
.
Storer
,
)
Interface
{
)
Interface
{
return
&
postageContract
{
return
&
postageContract
{
owner
:
owner
,
owner
:
owner
,
...
@@ -59,6 +64,7 @@ func New(
...
@@ -59,6 +64,7 @@ func New(
bzzTokenAddress
:
bzzTokenAddress
,
bzzTokenAddress
:
bzzTokenAddress
,
transactionService
:
transactionService
,
transactionService
:
transactionService
,
postageService
:
postageService
,
postageService
:
postageService
,
postageStorer
:
postageStorer
,
}
}
}
}
...
@@ -69,11 +75,12 @@ func (c *postageContract) sendApproveTransaction(ctx context.Context, amount *bi
...
@@ -69,11 +75,12 @@ func (c *postageContract) sendApproveTransaction(ctx context.Context, amount *bi
}
}
txHash
,
err
:=
c
.
transactionService
.
Send
(
ctx
,
&
transaction
.
TxRequest
{
txHash
,
err
:=
c
.
transactionService
.
Send
(
ctx
,
&
transaction
.
TxRequest
{
To
:
&
c
.
bzzTokenAddress
,
To
:
&
c
.
bzzTokenAddress
,
Data
:
callData
,
Data
:
callData
,
GasPrice
:
sctx
.
GetGasPrice
(
ctx
),
GasPrice
:
sctx
.
GetGasPrice
(
ctx
),
GasLimit
:
65000
,
GasLimit
:
65000
,
Value
:
big
.
NewInt
(
0
),
Value
:
big
.
NewInt
(
0
),
Description
:
"Approve tokens for postage operations"
,
})
})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
@@ -99,11 +106,12 @@ func (c *postageContract) sendCreateBatchTransaction(ctx context.Context, owner
...
@@ -99,11 +106,12 @@ func (c *postageContract) sendCreateBatchTransaction(ctx context.Context, owner
}
}
request
:=
&
transaction
.
TxRequest
{
request
:=
&
transaction
.
TxRequest
{
To
:
&
c
.
postageContractAddress
,
To
:
&
c
.
postageContractAddress
,
Data
:
callData
,
Data
:
callData
,
GasPrice
:
sctx
.
GetGasPrice
(
ctx
),
GasPrice
:
sctx
.
GetGasPrice
(
ctx
),
GasLimit
:
160000
,
GasLimit
:
160000
,
Value
:
big
.
NewInt
(
0
),
Value
:
big
.
NewInt
(
0
),
Description
:
"Postage batch creation"
,
}
}
txHash
,
err
:=
c
.
transactionService
.
Send
(
ctx
,
request
)
txHash
,
err
:=
c
.
transactionService
.
Send
(
ctx
,
request
)
...
@@ -123,6 +131,39 @@ func (c *postageContract) sendCreateBatchTransaction(ctx context.Context, owner
...
@@ -123,6 +131,39 @@ func (c *postageContract) sendCreateBatchTransaction(ctx context.Context, owner
return
receipt
,
nil
return
receipt
,
nil
}
}
func
(
c
*
postageContract
)
sendTopUpBatchTransaction
(
ctx
context
.
Context
,
batchID
[]
byte
,
topUpAmount
*
big
.
Int
)
(
*
types
.
Receipt
,
error
)
{
callData
,
err
:=
postageStampABI
.
Pack
(
"topUp"
,
common
.
BytesToHash
(
batchID
),
topUpAmount
)
if
err
!=
nil
{
return
nil
,
err
}
request
:=
&
transaction
.
TxRequest
{
To
:
&
c
.
postageContractAddress
,
Data
:
callData
,
GasPrice
:
sctx
.
GetGasPrice
(
ctx
),
GasLimit
:
160000
,
Value
:
big
.
NewInt
(
0
),
Description
:
"Postage batch top up"
,
}
txHash
,
err
:=
c
.
transactionService
.
Send
(
ctx
,
request
)
if
err
!=
nil
{
return
nil
,
err
}
receipt
,
err
:=
c
.
transactionService
.
WaitForReceipt
(
ctx
,
txHash
)
if
err
!=
nil
{
return
nil
,
err
}
if
receipt
.
Status
==
0
{
return
nil
,
transaction
.
ErrTransactionReverted
}
return
receipt
,
nil
}
func
(
c
*
postageContract
)
getBalance
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
{
func
(
c
*
postageContract
)
getBalance
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
{
callData
,
err
:=
erc20ABI
.
Pack
(
"balanceOf"
,
c
.
owner
)
callData
,
err
:=
erc20ABI
.
Pack
(
"balanceOf"
,
c
.
owner
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -204,6 +245,42 @@ func (c *postageContract) CreateBatch(ctx context.Context, initialBalance *big.I
...
@@ -204,6 +245,42 @@ func (c *postageContract) CreateBatch(ctx context.Context, initialBalance *big.I
return
nil
,
ErrBatchCreate
return
nil
,
ErrBatchCreate
}
}
func
(
c
*
postageContract
)
TopUpBatch
(
ctx
context
.
Context
,
batchID
[]
byte
,
topUpAmount
*
big
.
Int
)
error
{
batch
,
err
:=
c
.
postageStorer
.
Get
(
batchID
)
if
err
!=
nil
{
return
err
}
totalAmount
:=
big
.
NewInt
(
0
)
.
Mul
(
topUpAmount
,
big
.
NewInt
(
int64
(
1
<<
batch
.
Depth
)))
balance
,
err
:=
c
.
getBalance
(
ctx
)
if
err
!=
nil
{
return
err
}
if
balance
.
Cmp
(
totalAmount
)
<
0
{
return
ErrInsufficientFunds
}
_
,
err
=
c
.
sendApproveTransaction
(
ctx
,
totalAmount
)
if
err
!=
nil
{
return
err
}
receipt
,
err
:=
c
.
sendTopUpBatchTransaction
(
ctx
,
batch
.
ID
,
topUpAmount
)
if
err
!=
nil
{
return
err
}
for
_
,
ev
:=
range
receipt
.
Logs
{
if
ev
.
Address
==
c
.
postageContractAddress
&&
len
(
ev
.
Topics
)
>
0
&&
ev
.
Topics
[
0
]
==
batchTopUpTopic
{
return
nil
}
}
return
ErrBatchTopUp
}
type
batchCreatedEvent
struct
{
type
batchCreatedEvent
struct
{
BatchId
[
32
]
byte
BatchId
[
32
]
byte
TotalAmount
*
big
.
Int
TotalAmount
*
big
.
Int
...
...
pkg/postage/postagecontract/contract_test.go
View file @
81988b16
...
@@ -14,8 +14,11 @@ import (
...
@@ -14,8 +14,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/postage"
postagestoreMock
"github.com/ethersphere/bee/pkg/postage/batchstore/mock"
postageMock
"github.com/ethersphere/bee/pkg/postage/mock"
postageMock
"github.com/ethersphere/bee/pkg/postage/mock"
"github.com/ethersphere/bee/pkg/postage/postagecontract"
"github.com/ethersphere/bee/pkg/postage/postagecontract"
postagetesting
"github.com/ethersphere/bee/pkg/postage/testing"
"github.com/ethersphere/bee/pkg/transaction"
"github.com/ethersphere/bee/pkg/transaction"
transactionMock
"github.com/ethersphere/bee/pkg/transaction/mock"
transactionMock
"github.com/ethersphere/bee/pkg/transaction/mock"
)
)
...
@@ -85,6 +88,7 @@ func TestCreateBatch(t *testing.T) {
...
@@ -85,6 +88,7 @@ func TestCreateBatch(t *testing.T) {
}),
}),
),
),
postageMock
,
postageMock
,
postagestoreMock
.
New
(),
)
)
returnedID
,
err
:=
contract
.
CreateBatch
(
ctx
,
initialBalance
,
depth
,
false
,
label
)
returnedID
,
err
:=
contract
.
CreateBatch
(
ctx
,
initialBalance
,
depth
,
false
,
label
)
...
@@ -115,6 +119,7 @@ func TestCreateBatch(t *testing.T) {
...
@@ -115,6 +119,7 @@ func TestCreateBatch(t *testing.T) {
bzzTokenAddress
,
bzzTokenAddress
,
transactionMock
.
New
(),
transactionMock
.
New
(),
postageMock
.
New
(),
postageMock
.
New
(),
postagestoreMock
.
New
(),
)
)
_
,
err
:=
contract
.
CreateBatch
(
ctx
,
initialBalance
,
depth
,
false
,
label
)
_
,
err
:=
contract
.
CreateBatch
(
ctx
,
initialBalance
,
depth
,
false
,
label
)
...
@@ -140,6 +145,7 @@ func TestCreateBatch(t *testing.T) {
...
@@ -140,6 +145,7 @@ func TestCreateBatch(t *testing.T) {
}),
}),
),
),
postageMock
.
New
(),
postageMock
.
New
(),
postagestoreMock
.
New
(),
)
)
_
,
err
:=
contract
.
CreateBatch
(
ctx
,
initialBalance
,
depth
,
false
,
label
)
_
,
err
:=
contract
.
CreateBatch
(
ctx
,
initialBalance
,
depth
,
false
,
label
)
...
@@ -192,3 +198,157 @@ func TestLookupERC20Address(t *testing.T) {
...
@@ -192,3 +198,157 @@ func TestLookupERC20Address(t *testing.T) {
t
.
Fatalf
(
"got wrong erc20 address. wanted %v, got %v"
,
erc20Address
,
addr
)
t
.
Fatalf
(
"got wrong erc20 address. wanted %v, got %v"
,
erc20Address
,
addr
)
}
}
}
}
func
TestTopUpBatch
(
t
*
testing
.
T
)
{
defer
func
(
b
uint8
)
{
postagecontract
.
BucketDepth
=
b
}(
postagecontract
.
BucketDepth
)
postagecontract
.
BucketDepth
=
9
owner
:=
common
.
HexToAddress
(
"abcd"
)
postageStampAddress
:=
common
.
HexToAddress
(
"ffff"
)
bzzTokenAddress
:=
common
.
HexToAddress
(
"eeee"
)
ctx
:=
context
.
Background
()
topupBalance
:=
big
.
NewInt
(
100
)
t
.
Run
(
"ok"
,
func
(
t
*
testing
.
T
)
{
totalAmount
:=
big
.
NewInt
(
102400
)
txHashApprove
:=
common
.
HexToHash
(
"abb0"
)
txHashTopup
:=
common
.
HexToHash
(
"c3a7"
)
batch
:=
postagetesting
.
MustNewBatch
(
postagetesting
.
WithOwner
(
owner
.
Bytes
()))
batch
.
Depth
=
uint8
(
10
)
batch
.
BucketDepth
=
uint8
(
9
)
postageMock
:=
postageMock
.
New
(
postageMock
.
WithIssuer
(
postage
.
NewStampIssuer
(
"label"
,
"keyID"
,
batch
.
ID
,
batch
.
Value
,
batch
.
Depth
,
batch
.
BucketDepth
,
batch
.
Start
,
batch
.
Immutable
,
)))
batchStoreMock
:=
postagestoreMock
.
New
(
postagestoreMock
.
WithBatch
(
batch
))
expectedCallData
,
err
:=
postagecontract
.
PostageStampABI
.
Pack
(
"topUp"
,
common
.
BytesToHash
(
batch
.
ID
),
topupBalance
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
contract
:=
postagecontract
.
New
(
owner
,
postageStampAddress
,
bzzTokenAddress
,
transactionMock
.
New
(
transactionMock
.
WithSendFunc
(
func
(
ctx
context
.
Context
,
request
*
transaction
.
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
{
if
*
request
.
To
==
bzzTokenAddress
{
return
txHashApprove
,
nil
}
else
if
*
request
.
To
==
postageStampAddress
{
if
!
bytes
.
Equal
(
expectedCallData
[
:
64
],
request
.
Data
[
:
64
])
{
return
common
.
Hash
{},
fmt
.
Errorf
(
"got wrong call data. wanted %x, got %x"
,
expectedCallData
,
request
.
Data
)
}
return
txHashTopup
,
nil
}
return
common
.
Hash
{},
errors
.
New
(
"sent to wrong contract"
)
}),
transactionMock
.
WithWaitForReceiptFunc
(
func
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
{
if
txHash
==
txHashApprove
{
return
&
types
.
Receipt
{
Status
:
1
,
},
nil
}
else
if
txHash
==
txHashTopup
{
return
&
types
.
Receipt
{
Logs
:
[]
*
types
.
Log
{
newTopUpEvent
(
postageStampAddress
,
batch
),
},
Status
:
1
,
},
nil
}
return
nil
,
errors
.
New
(
"unknown tx hash"
)
}),
transactionMock
.
WithCallFunc
(
func
(
ctx
context
.
Context
,
request
*
transaction
.
TxRequest
)
(
result
[]
byte
,
err
error
)
{
if
*
request
.
To
==
bzzTokenAddress
{
return
totalAmount
.
FillBytes
(
make
([]
byte
,
32
)),
nil
}
return
nil
,
errors
.
New
(
"unexpected call"
)
}),
),
postageMock
,
batchStoreMock
,
)
err
=
contract
.
TopUpBatch
(
ctx
,
batch
.
ID
,
topupBalance
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
si
,
err
:=
postageMock
.
GetStampIssuer
(
batch
.
ID
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
si
==
nil
{
t
.
Fatal
(
"stamp issuer not set"
)
}
})
t
.
Run
(
"batch doesnt exist"
,
func
(
t
*
testing
.
T
)
{
errNotFound
:=
errors
.
New
(
"not found"
)
contract
:=
postagecontract
.
New
(
owner
,
postageStampAddress
,
bzzTokenAddress
,
transactionMock
.
New
(),
postageMock
.
New
(),
postagestoreMock
.
New
(
postagestoreMock
.
WithGetErr
(
errNotFound
,
0
)),
)
err
:=
contract
.
TopUpBatch
(
ctx
,
postagetesting
.
MustNewID
(),
topupBalance
)
if
!
errors
.
Is
(
err
,
errNotFound
)
{
t
.
Fatal
(
"expected error on topup of non existent batch"
)
}
})
t
.
Run
(
"insufficient funds"
,
func
(
t
*
testing
.
T
)
{
totalAmount
:=
big
.
NewInt
(
102399
)
batch
:=
postagetesting
.
MustNewBatch
(
postagetesting
.
WithOwner
(
owner
.
Bytes
()))
batchStoreMock
:=
postagestoreMock
.
New
(
postagestoreMock
.
WithBatch
(
batch
))
contract
:=
postagecontract
.
New
(
owner
,
postageStampAddress
,
bzzTokenAddress
,
transactionMock
.
New
(
transactionMock
.
WithCallFunc
(
func
(
ctx
context
.
Context
,
request
*
transaction
.
TxRequest
)
(
result
[]
byte
,
err
error
)
{
if
*
request
.
To
==
bzzTokenAddress
{
return
big
.
NewInt
(
0
)
.
Sub
(
totalAmount
,
big
.
NewInt
(
1
))
.
FillBytes
(
make
([]
byte
,
32
)),
nil
}
return
nil
,
errors
.
New
(
"unexpected call"
)
}),
),
postageMock
.
New
(),
batchStoreMock
,
)
err
:=
contract
.
TopUpBatch
(
ctx
,
batch
.
ID
,
topupBalance
)
if
!
errors
.
Is
(
err
,
postagecontract
.
ErrInsufficientFunds
)
{
t
.
Fatalf
(
"expected error %v. got %v"
,
postagecontract
.
ErrInsufficientFunds
,
err
)
}
})
}
func
newTopUpEvent
(
postageContractAddress
common
.
Address
,
batch
*
postage
.
Batch
)
*
types
.
Log
{
b
,
err
:=
postagecontract
.
PostageStampABI
.
Events
[
"BatchTopUp"
]
.
Inputs
.
NonIndexed
()
.
Pack
(
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
)
if
err
!=
nil
{
panic
(
err
)
}
return
&
types
.
Log
{
Address
:
postageContractAddress
,
Data
:
b
,
Topics
:
[]
common
.
Hash
{
postagecontract
.
BatchTopUpTopic
,
common
.
BytesToHash
(
batch
.
ID
)},
BlockNumber
:
batch
.
Start
+
1
,
}
}
pkg/postage/postagecontract/export_test.go
View file @
81988b16
...
@@ -7,4 +7,5 @@ package postagecontract
...
@@ -7,4 +7,5 @@ package postagecontract
var
(
var
(
PostageStampABI
=
postageStampABI
PostageStampABI
=
postageStampABI
BatchCreatedTopic
=
batchCreatedTopic
BatchCreatedTopic
=
batchCreatedTopic
BatchTopUpTopic
=
batchTopUpTopic
)
)
pkg/postage/postagecontract/mock/contract.go
View file @
81988b16
...
@@ -13,12 +13,17 @@ import (
...
@@ -13,12 +13,17 @@ import (
type
contractMock
struct
{
type
contractMock
struct
{
createBatch
func
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
createBatch
func
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
topupBatch
func
(
ctx
context
.
Context
,
id
[]
byte
,
amount
*
big
.
Int
)
error
}
}
func
(
c
*
contractMock
)
CreateBatch
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
{
func
(
c
*
contractMock
)
CreateBatch
(
ctx
context
.
Context
,
initialBalance
*
big
.
Int
,
depth
uint8
,
immutable
bool
,
label
string
)
([]
byte
,
error
)
{
return
c
.
createBatch
(
ctx
,
initialBalance
,
depth
,
immutable
,
label
)
return
c
.
createBatch
(
ctx
,
initialBalance
,
depth
,
immutable
,
label
)
}
}
func
(
c
*
contractMock
)
TopUpBatch
(
ctx
context
.
Context
,
batchID
[]
byte
,
amount
*
big
.
Int
)
error
{
return
c
.
topupBatch
(
ctx
,
batchID
,
amount
)
}
// Option is a an option passed to New
// Option is a an option passed to New
type
Option
func
(
*
contractMock
)
type
Option
func
(
*
contractMock
)
...
@@ -38,3 +43,9 @@ func WithCreateBatchFunc(f func(ctx context.Context, initialBalance *big.Int, de
...
@@ -38,3 +43,9 @@ func WithCreateBatchFunc(f func(ctx context.Context, initialBalance *big.Int, de
m
.
createBatch
=
f
m
.
createBatch
=
f
}
}
}
}
func
WithTopUpBatchFunc
(
f
func
(
ctx
context
.
Context
,
batchID
[]
byte
,
amount
*
big
.
Int
)
error
)
Option
{
return
func
(
m
*
contractMock
)
{
m
.
topupBatch
=
f
}
}
pkg/postage/service.go
View file @
81988b16
...
@@ -9,6 +9,7 @@ import (
...
@@ -9,6 +9,7 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"io"
"io"
"math/big"
"sync"
"sync"
"github.com/ethersphere/bee/pkg/storage"
"github.com/ethersphere/bee/pkg/storage"
...
@@ -34,7 +35,7 @@ type Service interface {
...
@@ -34,7 +35,7 @@ type Service interface {
StampIssuers
()
[]
*
StampIssuer
StampIssuers
()
[]
*
StampIssuer
GetStampIssuer
([]
byte
)
(
*
StampIssuer
,
error
)
GetStampIssuer
([]
byte
)
(
*
StampIssuer
,
error
)
IssuerUsable
(
*
StampIssuer
)
bool
IssuerUsable
(
*
StampIssuer
)
bool
Batch
Creation
Listener
Batch
Event
Listener
io
.
Closer
io
.
Closer
}
}
...
@@ -87,10 +88,10 @@ func (ps *service) Add(st *StampIssuer) {
...
@@ -87,10 +88,10 @@ func (ps *service) Add(st *StampIssuer) {
ps
.
issuers
=
append
(
ps
.
issuers
,
st
)
ps
.
issuers
=
append
(
ps
.
issuers
,
st
)
}
}
// Handle
implements the BatchCreation
Listener interface. This is fired on receiving
// Handle
Create implements the BatchEvent
Listener interface. This is fired on receiving
// a batch creation event from the blockchain listener to ensure that if a stamp
// a batch creation event from the blockchain listener to ensure that if a stamp
// issuer was not created initially, we will create it here.
// issuer was not created initially, we will create it here.
func
(
ps
*
service
)
Handle
(
b
*
Batch
)
{
func
(
ps
*
service
)
Handle
Create
(
b
*
Batch
)
{
ps
.
Add
(
NewStampIssuer
(
ps
.
Add
(
NewStampIssuer
(
"recovered"
,
"recovered"
,
string
(
b
.
Owner
),
string
(
b
.
Owner
),
...
@@ -103,6 +104,22 @@ func (ps *service) Handle(b *Batch) {
...
@@ -103,6 +104,22 @@ func (ps *service) Handle(b *Batch) {
))
))
}
}
// HandleTopUp implements the BatchEventListener interface. This is fired on receiving
// a batch topup event from the blockchain to update stampissuer details
func
(
ps
*
service
)
HandleTopUp
(
batchID
[]
byte
,
newValue
*
big
.
Int
)
{
ps
.
lock
.
Lock
()
defer
ps
.
lock
.
Unlock
()
for
_
,
v
:=
range
ps
.
issuers
{
if
bytes
.
Equal
(
batchID
,
v
.
data
.
BatchID
)
{
if
newValue
.
Cmp
(
v
.
data
.
BatchAmount
)
>
0
{
v
.
data
.
BatchAmount
=
newValue
}
return
}
}
}
// StampIssuers returns the currently active stamp issuers.
// StampIssuers returns the currently active stamp issuers.
func
(
ps
*
service
)
StampIssuers
()
[]
*
StampIssuer
{
func
(
ps
*
service
)
StampIssuers
()
[]
*
StampIssuer
{
ps
.
lock
.
Lock
()
ps
.
lock
.
Lock
()
...
...
pkg/postage/service_test.go
View file @
81988b16
...
@@ -83,9 +83,6 @@ func TestGetStampIssuer(t *testing.T) {
...
@@ -83,9 +83,6 @@ func TestGetStampIssuer(t *testing.T) {
}
}
ps
.
Add
(
postage
.
NewStampIssuer
(
string
(
id
),
""
,
id
,
big
.
NewInt
(
3
),
16
,
8
,
validBlockNumber
+
shift
,
true
))
ps
.
Add
(
postage
.
NewStampIssuer
(
string
(
id
),
""
,
id
,
big
.
NewInt
(
3
),
16
,
8
,
validBlockNumber
+
shift
,
true
))
}
}
b
:=
postagetesting
.
MustNewBatch
()
b
.
Start
=
validBlockNumber
ps
.
Handle
(
b
)
t
.
Run
(
"found"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"found"
,
func
(
t
*
testing
.
T
)
{
for
_
,
id
:=
range
ids
[
1
:
4
]
{
for
_
,
id
:=
range
ids
[
1
:
4
]
{
st
,
err
:=
ps
.
GetStampIssuer
(
id
)
st
,
err
:=
ps
.
GetStampIssuer
(
id
)
...
@@ -112,6 +109,9 @@ func TestGetStampIssuer(t *testing.T) {
...
@@ -112,6 +109,9 @@ func TestGetStampIssuer(t *testing.T) {
}
}
})
})
t
.
Run
(
"recovered"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"recovered"
,
func
(
t
*
testing
.
T
)
{
b
:=
postagetesting
.
MustNewBatch
()
b
.
Start
=
validBlockNumber
ps
.
HandleCreate
(
b
)
st
,
err
:=
ps
.
GetStampIssuer
(
b
.
ID
)
st
,
err
:=
ps
.
GetStampIssuer
(
b
.
ID
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"expected no error, got %v"
,
err
)
t
.
Fatalf
(
"expected no error, got %v"
,
err
)
...
@@ -120,4 +120,14 @@ func TestGetStampIssuer(t *testing.T) {
...
@@ -120,4 +120,14 @@ func TestGetStampIssuer(t *testing.T) {
t
.
Fatal
(
"wrong issuer returned"
)
t
.
Fatal
(
"wrong issuer returned"
)
}
}
})
})
t
.
Run
(
"topup"
,
func
(
t
*
testing
.
T
)
{
ps
.
HandleTopUp
(
ids
[
1
],
big
.
NewInt
(
10
))
_
,
err
:=
ps
.
GetStampIssuer
(
ids
[
1
])
if
err
!=
nil
{
t
.
Fatalf
(
"expected no error, got %v"
,
err
)
}
if
ps
.
StampIssuers
()[
0
]
.
Amount
()
.
Cmp
(
big
.
NewInt
(
10
))
!=
0
{
t
.
Fatalf
(
"expected amount %d got %d"
,
10
,
ps
.
StampIssuers
()[
0
]
.
Amount
()
.
Int64
())
}
})
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment