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

Bug/include nonce in siktx #1133

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
10 changes: 9 additions & 1 deletion apiclient/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,26 @@ func (c *HTTPclient) Account(address string) (*api.Account, error) {
}

// Transfer sends tokens from the account associated with the client to the given address.
// The nonce is automatically calculated from the account information.
// Returns the transaction hash.
func (c *HTTPclient) Transfer(to common.Address, amount uint64) (types.HexBytes, error) {
acc, err := c.Account("")
if err != nil {
return nil, err
}
return c.TransferWithNonce(to, amount, acc.Nonce)
}

// TransferWithNonce sends tokens from the account associated with the client to the given address.
// Returns the transaction hash.
func (c *HTTPclient) TransferWithNonce(to common.Address, amount uint64, nonce uint32) (types.HexBytes, error) {
var err error
stx := models.SignedTx{}
stx.Tx, err = proto.Marshal(&models.Tx{
Payload: &models.Tx_SendTokens{
SendTokens: &models.SendTokensTx{
Txtype: models.TxType_SET_ACCOUNT_INFO_URI,
Nonce: acc.Nonce,
Nonce: nonce,
From: c.account.Address().Bytes(),
To: to.Bytes(),
Value: amount,
Expand Down
65 changes: 46 additions & 19 deletions cmd/end2endtest/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"strings"
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -150,6 +151,8 @@ func testSendTokens(api *apiclient.HTTPclient, aliceKeys, bobKeys *ethereum.Sign
// both pay 2 for each tx
// resulting in balance 52 for alice
// and 44 for bob
// In addition, we send a couple of token txs to burn address to increase the nonce,
// without waiting for them to be mined (this tests that the mempool transactions are properly ordered).

txCost, err := api.TransactionCost(models.TxType_SEND_TOKENS)
if err != nil {
Expand Down Expand Up @@ -181,23 +184,47 @@ func testSendTokens(api *apiclient.HTTPclient, aliceKeys, bobKeys *ethereum.Sign
// try to send tokens at the same time:
// alice sends 1/4 of her balance to bob
// sends 1/3 of his balance to alice
amountAtoB := aliceAcc.Balance / 4
amountBtoA := bobAcc.Balance / 3

txhasha, err := alice.Transfer(bobKeys.Address(), amountAtoB)
if err != nil {
return fmt.Errorf("cannot send tokens: %v", err)
}
log.Infof("alice sent %d tokens to bob", amountAtoB)
log.Debugf("tx hash is %x", txhasha)
// Subtract 1 + txCost from each since we are sending an extra tx to increase the nonce to the burn address
amountAtoB := (aliceAcc.Balance) / 4
amountBtoA := (bobAcc.Balance) / 3

// send a couple of token txs to increase the nonce, without waiting for them to be mined
// this tests that the mempool transactions are properly ordered.
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
log.Warnf("send transactions with nonce+1, should not be mined before the others")
// send 1 token to burn address with nonce + 1 (should be mined after the other txs)
if _, err = alice.TransferWithNonce(state.BurnAddress, 1, aliceAcc.Nonce+1); err != nil {
log.Fatalf("cannot burn tokens: %v", err)
}
if _, err = bob.TransferWithNonce(state.BurnAddress, 1, bobAcc.Nonce+1); err != nil {
log.Fatalf("cannot burn tokens: %v", err)
}
wg.Done()
}()
log.Warnf("waiting 6 seconds to let the burn txs be sent")
time.Sleep(6 * time.Second)
var txhasha, txhashb []byte
wg.Add(1)
go func() {
txhasha, err = alice.TransferWithNonce(bobKeys.Address(), amountAtoB, aliceAcc.Nonce)
if err != nil {
log.Fatalf("cannot send tokens: %v", err)
}
log.Infof("alice sent %d tokens to bob", amountAtoB)
log.Debugf("tx hash is %x", txhasha)

txhashb, err := bob.Transfer(aliceKeys.Address(), amountBtoA)
if err != nil {
return fmt.Errorf("cannot send tokens: %v", err)
}
log.Infof("bob sent %d tokens to alice", amountBtoA)
log.Debugf("tx hash is %x", txhashb)
txhashb, err = bob.TransferWithNonce(aliceKeys.Address(), amountBtoA, bobAcc.Nonce)
if err != nil {
log.Fatalf("cannot send tokens: %v", err)
}
log.Infof("bob sent %d tokens to alice", amountBtoA)
log.Debugf("tx hash is %x", txhashb)
wg.Done()
}()

wg.Wait()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*40)
defer cancel()
txrefa, err := api.WaitUntilTxIsMined(ctx, txhasha)
Expand All @@ -216,12 +243,12 @@ func testSendTokens(api *apiclient.HTTPclient, aliceKeys, bobKeys *ethereum.Sign
_ = api.WaitUntilNextBlock()

// now check the resulting state
if err := checkAccountNonceAndBalance(alice, aliceAcc.Nonce+1,
aliceAcc.Balance-amountAtoB-txCost+amountBtoA); err != nil {
if err := checkAccountNonceAndBalance(alice, aliceAcc.Nonce+2,
aliceAcc.Balance-amountAtoB-(2*txCost+1)+amountBtoA); err != nil {
return err
}
if err := checkAccountNonceAndBalance(bob, bobAcc.Nonce+1,
bobAcc.Balance-amountBtoA-txCost+amountAtoB); err != nil {
if err := checkAccountNonceAndBalance(bob, bobAcc.Nonce+2,
bobAcc.Balance-amountBtoA-(2*txCost+1)+amountAtoB); err != nil {
return err
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/end2endtest/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ func (t *e2eElection) generateProofs(csp *ethereum.SignKeys, voterAccts []*ether
wg sync.WaitGroup
vcount int32
)
// Wait for the next block to assure the SIK root is updated
if err := t.api.WaitUntilNextBlock(); err != nil {
return err
}
errorChan := make(chan error)
t.voters = new(sync.Map)
addNaccounts := func(accounts []*ethereum.SignKeys) {
Expand Down
2 changes: 1 addition & 1 deletion dockerfiles/testsuite/env.gateway0
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ VOCDONI_VOCHAIN_NOWAITSYNC=True
VOCDONI_METRICS_ENABLED=True
VOCDONI_METRICS_REFRESHINTERVAL=5
VOCDONI_CHAIN=dev
VOCDONI_SIGNINGKEY=e0f1412b86d6ca9f2b318f1d243ef50be23d315a2e6c1c3035bc72d44c8b2f90
VOCDONI_SIGNINGKEY=e0f1412b86d6ca9f2b318f1d243ef50be23d315a2e6c1c3035bc72d44c8b2f90 # 0x88a499cEf9D1330111b41360173967c9C1bf703f
14 changes: 1 addition & 13 deletions dockerfiles/testsuite/genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,8 @@
],
"accounts":[
{
"address":"0xccEc2c2D658261Fbdc40b04FEc06d49057242D39",
"balance":10000000
},
{
"address":"0x776d858D17C8018F07899dB535866EBf805a32E0",
"balance":10000000
},
{
"address":"0x074fcAacb8B01850539eaE7E9fEE8dc94549db96",
"balance":10000000
},
{
"address":"0x88a499cEf9D1330111b41360173967c9C1bf703f",
"balance":10000000
"balance":1000000000000
}
],
"treasurer": "0xfe10DAB06D636647f4E40dFd56599da9eF66Db1c",
Expand Down
11 changes: 7 additions & 4 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path"
"runtime/debug"
"strings"
"time"

"github.com/rs/zerolog"
Expand Down Expand Up @@ -89,11 +90,9 @@ func (*invalidCharChecker) Write(p []byte) (int, error) {
return len(p), nil
}

// Init initializes the logger. Output can be either "stdout/stderr/<filePath>".
// Log level can be "debug/info/warn/error".
// errorOutput is an optional filename which only receives Warning and Error messages.
func Init(level, output string, errorOutput io.Writer) {
var out io.Writer
outputs := []io.Writer{}
switch output {
case "stdout":
out = os.Stdout
Expand All @@ -107,12 +106,16 @@ func Init(level, output string, errorOutput io.Writer) {
panic(fmt.Sprintf("cannot create log output: %v", err))
}
out = f
if strings.HasSuffix(output, ".json") {
outputs = append(outputs, f)
out = os.Stdout
}
}
out = zerolog.ConsoleWriter{
Out: out,
TimeFormat: time.RFC3339Nano,
}
outputs := []io.Writer{out}
outputs = append(outputs, out)

if errorOutput != nil {
outputs = append(outputs, &errorLevelWriter{zerolog.ConsoleWriter{
Expand Down
18 changes: 15 additions & 3 deletions tree/arbo/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ var (

// Tree defines the struct that implements the MerkleTree functionalities
type Tree struct {
sync.Mutex
sync.RWMutex

db db.Database
maxLevels int
Expand Down Expand Up @@ -181,7 +181,7 @@ func (t *Tree) RootWithTx(rTx db.Reader) ([]byte, error) {
return rTx.Get(dbKeyRoot)
}

func (*Tree) setRoot(wTx db.WriteTx, root []byte) error {
func (t *Tree) setRoot(wTx db.WriteTx, root []byte) error {
return wTx.Set(dbKeyRoot, root)
}

Expand Down Expand Up @@ -325,7 +325,6 @@ func (t *Tree) Update(k, v []byte) error {
func (t *Tree) UpdateWithTx(wTx db.WriteTx, k, v []byte) error {
t.Lock()
defer t.Unlock()

if !t.editable() {
return ErrSnapshotNotEditable
}
Expand Down Expand Up @@ -521,6 +520,9 @@ func (t *Tree) Get(k []byte) ([]byte, []byte, error) {
// ErrKeyNotFound, and in the leafK & leafV parameters will be placed the data
// found in the tree in the leaf that was on the path going to the input key.
func (t *Tree) GetWithTx(rTx db.Reader, k []byte) ([]byte, []byte, error) {
t.RLock()
defer t.RUnlock()

keyPath, err := keyPathFromKey(t.maxLevels, k)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -602,6 +604,8 @@ func (t *Tree) SetRoot(root []byte) error {

// SetRootWithTx sets the root to the given root using the given db.WriteTx
func (t *Tree) SetRootWithTx(wTx db.WriteTx, root []byte) error {
t.Lock()
defer t.Unlock()
if !t.editable() {
return ErrSnapshotNotEditable
}
Expand All @@ -620,6 +624,8 @@ func (t *Tree) SetRootWithTx(wTx db.WriteTx, root []byte) error {
// The provided root must be a valid existing intermediate node in the tree.
// The list of roots for a level can be obtained using tree.RootsFromLevel().
func (t *Tree) Snapshot(fromRoot []byte) (*Tree, error) {
t.Lock()
defer t.Unlock()
// allow to define which root to use
if fromRoot == nil {
var err error
Expand Down Expand Up @@ -672,6 +678,8 @@ func (t *Tree) IterateWithTx(rTx db.Reader, fromRoot []byte, f func([]byte, []by
return err
}
}
t.RLock()
defer t.RUnlock()
return t.iter(rTx, fromRoot, f)
}

Expand All @@ -687,6 +695,8 @@ func (t *Tree) IterateWithStop(fromRoot []byte, f func(int, []byte, []byte) bool
return err
}
}
t.RLock()
defer t.RUnlock()
return t.iterWithStop(t.db, fromRoot, 0, f)
}

Expand All @@ -701,6 +711,8 @@ func (t *Tree) IterateWithStopWithTx(rTx db.Reader, fromRoot []byte, f func(int,
return err
}
}
t.RLock()
defer t.RUnlock()
return t.iterWithStop(rTx, fromRoot, 0, f)
}

Expand Down
4 changes: 0 additions & 4 deletions vochain/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,10 +626,6 @@ func TestMintTokensTx(t *testing.T) {
if err := testMintTokensTx(t, &notTreasurer, app, toAccAddr, 100, 1); err == nil {
t.Fatal(err)
}
// should fail minting if invalid nonce
if err := testMintTokensTx(t, &signer, app, toAccAddr, 100, rand.Uint32()); err == nil {
t.Fatal(err)
}

// get account
toAcc, err := app.State.GetAccount(toAccAddr, false)
Expand Down
Loading
Loading