Skip to content
Snippets Groups Projects
Unverified Commit 4877cebd authored by jkrvivian's avatar jkrvivian
Browse files

Add colored tokens test

parent a2779619
No related branches found
No related tags found
No related merge requests found
...@@ -17,8 +17,8 @@ import ( ...@@ -17,8 +17,8 @@ import (
"github.com/iotaledger/goshimmer/plugins/metrics" "github.com/iotaledger/goshimmer/plugins/metrics"
"github.com/iotaledger/goshimmer/plugins/portcheck" "github.com/iotaledger/goshimmer/plugins/portcheck"
"github.com/iotaledger/goshimmer/plugins/profiling" "github.com/iotaledger/goshimmer/plugins/profiling"
"github.com/iotaledger/goshimmer/plugins/testsnapshots"
"github.com/iotaledger/goshimmer/plugins/sync" "github.com/iotaledger/goshimmer/plugins/sync"
"github.com/iotaledger/goshimmer/plugins/testsnapshots"
"github.com/iotaledger/hive.go/node" "github.com/iotaledger/hive.go/node"
) )
......
...@@ -25,8 +25,6 @@ const ( ...@@ -25,8 +25,6 @@ const (
dkgMaxTries = 50 dkgMaxTries = 50
exitStatusSuccessful = 0 exitStatusSuccessful = 0
SnapShotFirstAddress = "JaMauTaTSVBNc13edCCvBK9fZxZ1KKW5fXegT1B7N9jY"
) )
var ( var (
......
...@@ -100,94 +100,143 @@ func CheckForMessageIds(t *testing.T, peers []*framework.Peer, ids map[string]Da ...@@ -100,94 +100,143 @@ func CheckForMessageIds(t *testing.T, peers []*framework.Peer, ids map[string]Da
} }
} }
// SendValueMessage sends a value message on a given peer and returns the transaction ID. // SendValueMessagesOnFaucet sends funds to peers from the faucet and returns the transaction ID.
func SendValueMessagesOnFaucet(t *testing.T, peers []*framework.Peer) (txId string, addrBalance map[string]int64) { func SendValueMessagesOnFaucet(t *testing.T, peers []*framework.Peer) (txIds []string, addrBalance map[string]map[balance.Color]int64) {
// initiate addrBalance map
addrBalance = make(map[string]map[balance.Color]int64)
for _, p := range peers {
addr := p.Seed().Address(0).String()
addrBalance[addr] = make(map[balance.Color]int64)
addrBalance[addr][balance.ColorIOTA] = 0
}
faucetPeer := peers[0] faucetPeer := peers[0]
sigScheme := signaturescheme.ED25519(*faucetPeer.Seed().KeyPair(0)) faucetAddrStr := faucetPeer.Seed().Address(0).String()
// send the same funds to the original address
remainAddr := faucetPeer.Seed().Address(0)
var sentValue int64 = 0
// prepare inputs // get faucet balances
unspentOutputs, err := faucetPeer.GetUnspentOutputs([]string{framework.SnapShotFirstAddress}) unspentOutputs, err := faucetPeer.GetUnspentOutputs([]string{faucetAddrStr})
require.NoErrorf(t, err, "Could not get unspent outputs on %s", faucetPeer.String()) require.NoErrorf(t, err, "Could not get unspent outputs on %s", faucetPeer.String())
value := unspentOutputs.UnspentOutputs[0].OutputIDs[0].Balances[0].Value addrBalance[faucetAddrStr][balance.ColorIOTA] = unspentOutputs.UnspentOutputs[0].OutputIDs[0].Balances[0].Value
// send funds to other peers
for i := 1; i < len(peers); i++ {
fail, txId := SendIotaValueMessages(t, faucetPeer, peers[i], addrBalance)
require.False(t, fail)
txIds = append(txIds, txId)
// let the transaction propagate
time.Sleep(1 * time.Second)
}
return
}
// SendValueMessagesOnRandomPeer sends IOTA tokens on random peer and saves the sent message token to a map.
func SendValueMessagesOnRandomPeer(t *testing.T, peers []*framework.Peer, addrBalance map[string]map[balance.Color]int64, numMessages int) (txIds []string) {
for i := 0; i < numMessages; i++ {
from := rand.Intn(len(peers))
to := rand.Intn(len(peers))
fail, txId := SendIotaValueMessages(t, peers[from], peers[to], addrBalance)
if fail {
i--
continue
}
// attach tx id
txIds = append(txIds, txId)
// let the transaction propagate
time.Sleep(1 * time.Second)
}
return
}
// SendIotaValueMessages sends IOTA token from and to a given peer and returns the transaction ID.
// The same addresses are used in each round
func SendIotaValueMessages(t *testing.T, from *framework.Peer, to *framework.Peer, addrBalance map[string]map[balance.Color]int64) (fail bool, txId string) {
var sentValue int64 = 100
sigScheme := signaturescheme.ED25519(*from.Seed().KeyPair(0))
inputAddr := from.Seed().Address(0)
outputAddr := to.Seed().Address(0)
out, err := transaction.OutputIDFromBase58(unspentOutputs.UnspentOutputs[0].OutputIDs[0].ID) // abort if no unspent outputs
require.NoErrorf(t, err, "Invalid unspent outputs ID on %s", faucetPeer.String()) if addrBalance[inputAddr.String()][balance.ColorIOTA] < sentValue {
return true, ""
}
// prepare inputs
resp, err := from.GetUnspentOutputs([]string{inputAddr.String()})
require.NoErrorf(t, err, "Could not get unspent outputs on %s", from.String())
availableValue := resp.UnspentOutputs[0].OutputIDs[0].Balances[0].Value
out, err := transaction.OutputIDFromBase58(resp.UnspentOutputs[0].OutputIDs[0].ID)
require.NoErrorf(t, err, "Invalid unspent outputs ID on %s", from.String())
inputs := transaction.NewInputs([]transaction.OutputID{out}...) inputs := transaction.NewInputs([]transaction.OutputID{out}...)
// prepare outputs // prepare outputs
outmap := map[address.Address][]*balance.Balance{} outmap := map[address.Address][]*balance.Balance{}
addrBalance = make(map[string]int64) if inputAddr == outputAddr {
sentValue = availableValue
// send funds to other peers, skip faucet node }
for i := 1; i < len(peers); i++ {
addr := peers[i].Seed().Address(0)
// set balances // set balances
balances := []*balance.Balance{balance.New(balance.ColorIOTA, 100)} outmap[outputAddr] = []*balance.Balance{balance.New(balance.ColorIOTA, sentValue)}
outmap[addr] = balances
sentValue += 100
// set return map
addrBalance[addr.String()] = 100
}
outputs := transaction.NewOutputs(outmap) outputs := transaction.NewOutputs(outmap)
// handle remain address // handle remain address
outputs.Add(remainAddr, []*balance.Balance{balance.New(balance.ColorIOTA, value-sentValue)}) if availableValue > sentValue {
addrBalance[remainAddr.String()] = value - sentValue outputs.Add(inputAddr, []*balance.Balance{balance.New(balance.ColorIOTA, availableValue-sentValue)})
}
// sign transaction // sign transaction
txn := transaction.New(inputs, outputs).Sign(sigScheme) txn := transaction.New(inputs, outputs).Sign(sigScheme)
// send transaction // send transaction
txId, err = faucetPeer.SendTransaction(txn.Bytes()) txId, err = from.SendTransaction(txn.Bytes())
require.NoErrorf(t, err, "Could not send transaction on %s", faucetPeer.String()) require.NoErrorf(t, err, "Could not send transaction on %s", from.String())
return addrBalance[inputAddr.String()][balance.ColorIOTA] -= sentValue
} addrBalance[outputAddr.String()][balance.ColorIOTA] += sentValue
// SendDataMessagesOnRandomPeer sends data messages on a random peer and saves the sent message to a map. return false, txId
func SendValueMessagesOnRandomPeer(t *testing.T, peers []*framework.Peer, addrBalance map[string]int64, numMessages int) {
addrMap := make(map[int]string)
for i, p := range peers {
addrMap[i] = p.Seed().Address(0).String()
} }
// SendColoredValueMessagesOnRandomPeer sends colored token on a random peer and saves the sent token to a map.
func SendColoredValueMessagesOnRandomPeer(t *testing.T, peers []*framework.Peer, addrBalance map[string]map[balance.Color]int64, numMessages int) (txIds []string) {
for i := 0; i < numMessages; i++ { for i := 0; i < numMessages; i++ {
from := rand.Intn(len(peers)) from := rand.Intn(len(peers))
to := rand.Intn(len(peers)) to := rand.Intn(len(peers))
sentValue := SendValueMessages(t, peers[from], peers[to], addrBalance) fail, txId := SendColoredValueMessage(t, peers[from], peers[to], addrBalance)
if fail {
// update balance
addrBalance[addrMap[from]] -= sentValue
addrBalance[addrMap[to]] += sentValue
if sentValue == 0 {
i-- i--
continue
} }
time.Sleep(5 * time.Second)
// attach tx id
txIds = append(txIds, txId)
// let the transaction propagate
time.Sleep(1 * time.Second)
} }
return return
} }
// SendValueMessage sends a value message from and to a given peer and returns the transaction ID. // SendColoredValueMessage sends a colored tokens from and to a given peer and returns the transaction ID.
// for testing convenience, the same addresses are used in each round // The same addresses are used in each round
func SendValueMessages(t *testing.T, from *framework.Peer, to *framework.Peer, addrBalance map[string]int64) (sent int64) { func SendColoredValueMessage(t *testing.T, from *framework.Peer, to *framework.Peer, addrBalance map[string]map[balance.Color]int64) (fail bool, txId string) {
sigScheme := signaturescheme.ED25519(*from.Seed().KeyPair(0)) sigScheme := signaturescheme.ED25519(*from.Seed().KeyPair(0))
inputAddr := from.Seed().Address(0) inputAddr := from.Seed().Address(0)
outputAddr := to.Seed().Address(0) outputAddr := to.Seed().Address(0)
// skip if from peer has no balance
if addrBalance[inputAddr.String()] == 0 {
return 0
}
// prepare inputs // prepare inputs
resp, err := from.GetUnspentOutputs([]string{inputAddr.String()}) resp, err := from.GetUnspentOutputs([]string{inputAddr.String()})
require.NoErrorf(t, err, "Could not get unspent outputs on %s", from.String()) require.NoErrorf(t, err, "Could not get unspent outputs on %s", from.String())
value := resp.UnspentOutputs[0].OutputIDs[0].Balances[0].Value
// abort if no unspent outputs
if len(resp.UnspentOutputs[0].OutputIDs) == 0 {
return true, ""
}
out, err := transaction.OutputIDFromBase58(resp.UnspentOutputs[0].OutputIDs[0].ID) out, err := transaction.OutputIDFromBase58(resp.UnspentOutputs[0].OutputIDs[0].ID)
require.NoErrorf(t, err, "Invalid unspent outputs ID on %s", from.String()) require.NoErrorf(t, err, "Invalid unspent outputs ID on %s", from.String())
...@@ -195,24 +244,105 @@ func SendValueMessages(t *testing.T, from *framework.Peer, to *framework.Peer, a ...@@ -195,24 +244,105 @@ func SendValueMessages(t *testing.T, from *framework.Peer, to *framework.Peer, a
// prepare outputs // prepare outputs
outmap := map[address.Address][]*balance.Balance{} outmap := map[address.Address][]*balance.Balance{}
bs := []*balance.Balance{}
var outputs *transaction.Outputs
var availableIOTA int64
availableBalances := resp.UnspentOutputs[0].OutputIDs[0].Balances
newColor := false
// set balances // set balances
balances := []*balance.Balance{balance.New(balance.ColorIOTA, value)} if len(availableBalances) > 1 {
outmap[outputAddr] = balances // the balances contain more than one color, send it all
outputs := transaction.NewOutputs(outmap) for _, b := range availableBalances {
value := b.Value
color := getColorFromString(b.Color)
bs = append(bs, balance.New(color, value))
// update balance list
addrBalance[inputAddr.String()][color] -= value
if _, ok := addrBalance[outputAddr.String()][color]; ok {
addrBalance[outputAddr.String()][color] += value
} else {
addrBalance[outputAddr.String()][color] = value
}
}
} else {
// create new colored token if inputs only contain IOTA
// half of availableIota tokens remain IOTA, else get recolored
newColor = true
availableIOTA = availableBalances[0].Value
bs = append(bs, balance.New(balance.ColorIOTA, availableIOTA/2))
bs = append(bs, balance.New(balance.ColorNew, availableIOTA/2))
// update balance list
addrBalance[inputAddr.String()][balance.ColorIOTA] -= availableIOTA
addrBalance[outputAddr.String()][balance.ColorIOTA] += availableIOTA / 2
}
outmap[outputAddr] = bs
outputs = transaction.NewOutputs(outmap)
// sign transaction // sign transaction
txn := transaction.New(inputs, outputs).Sign(sigScheme) txn := transaction.New(inputs, outputs).Sign(sigScheme)
// send transaction // send transaction
_, err = from.SendTransaction(txn.Bytes()) txId, err = from.SendTransaction(txn.Bytes())
require.NoErrorf(t, err, "Could not send transaction on %s", from.String()) require.NoErrorf(t, err, "Could not send transaction on %s", from.String())
return value // FIXME: the new color should be txn ID
if newColor {
if _, ok := addrBalance[outputAddr.String()][balance.ColorNew]; ok {
addrBalance[outputAddr.String()][balance.ColorNew] += availableIOTA / 2
} else {
addrBalance[outputAddr.String()][balance.ColorNew] = availableIOTA / 2
}
//addrBalance[outputAddr.String()][getColorFromString(txId)] = availableIOTA / 2
}
return false, txId
}
func getColorFromString(colorStr string) (color balance.Color) {
if colorStr == "IOTA" {
color = balance.ColorIOTA
} else {
t, _ := transaction.IDFromBase58(colorStr)
color, _, _ = balance.ColorFromBytes(t.Bytes())
}
return
} }
// CheckBalances performs checks to make sure that all peers have the same ledger state. // CheckBalances performs checks to make sure that all peers have the same ledger state.
func CheckBalances(t *testing.T, peers []*framework.Peer, addrBalance map[string]int64, checkSynchronized bool) { func CheckBalances(t *testing.T, peers []*framework.Peer, addrBalance map[string]map[balance.Color]int64) {
for _, peer := range peers {
for addr, b := range addrBalance {
sum := make(map[balance.Color]int64)
resp, err := peer.GetUnspentOutputs([]string{addr})
require.NoError(t, err)
assert.Equal(t, addr, resp.UnspentOutputs[0].Address)
// calculate the balances of each color coin
for _, unspents := range resp.UnspentOutputs[0].OutputIDs {
for _, b := range unspents.Balances {
color := getColorFromString(b.Color)
if _, ok := sum[color]; ok {
sum[color] += b.Value
} else {
sum[color] = b.Value
}
}
}
// check balances
for color, value := range sum {
assert.Equal(t, b[color], value)
}
}
}
}
// CheckTransactions performs checks to make sure that all peers have received all transactions .
func CheckTransactions(t *testing.T, peers []*framework.Peer, transactionIDs []string, checkSynchronized bool) {
for _, peer := range peers { for _, peer := range peers {
if checkSynchronized { if checkSynchronized {
// check that the peer sees itself as synchronized // check that the peer sees itself as synchronized
...@@ -221,18 +351,12 @@ func CheckBalances(t *testing.T, peers []*framework.Peer, addrBalance map[string ...@@ -221,18 +351,12 @@ func CheckBalances(t *testing.T, peers []*framework.Peer, addrBalance map[string
require.True(t, info.Synced) require.True(t, info.Synced)
} }
for addr, b := range addrBalance { for _, txId := range transactionIDs {
var iotas int64 = 0 resp, err := peer.GetTransactionByID(txId)
resp, err := peer.GetUnspentOutputs([]string{addr})
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, addr, resp.UnspentOutputs[0].Address)
// calculate the total iotas of an address // check inclusion state
for _, unspents := range resp.UnspentOutputs[0].OutputIDs { assert.True(t, resp.InclusionState.Confirmed)
iotas += unspents.Balances[0].Value
assert.Equal(t, balance.ColorIOTA.String(), unspents.Balances[0].Color)
}
assert.Equal(t, b, iotas)
} }
} }
} }
......
...@@ -9,31 +9,38 @@ import ( ...@@ -9,31 +9,38 @@ import (
) )
// TestPersistence issues messages on random peers, restarts them and checks for persistence after restart. // TestPersistence issues messages on random peers, restarts them and checks for persistence after restart.
func TestPersistence(t *testing.T) { func TestValueIotaPersistence(t *testing.T) {
n, err := f.CreateNetwork("value_TestPersistence", 4, 2) n, err := f.CreateNetwork("valueIota_TestPersistence", 4, 2)
require.NoError(t, err) require.NoError(t, err)
defer tests.ShutdownNetwork(t, n) defer tests.ShutdownNetwork(t, n)
// wait for peers to change their state to synchronized // wait for peers to change their state to synchronized
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
// master node issue transaction to all peers in the network // master node sends funds to all peers in the network
_, addrBalance := tests.SendValueMessagesOnFaucet(t, n.Peers()) txIds, addrBalance := tests.SendValueMessagesOnFaucet(t, n.Peers())
// wait for messages to be gossiped // wait for messages to be gossiped
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
// 2. check whether all issued messages are available on all nodes // check whether the first issued transaction is available on all nodes, and confirmed
tests.CheckBalances(t, n.Peers(), addrBalance, true) tests.CheckTransactions(t, n.Peers(), txIds, true)
// check ledger state
tests.CheckBalances(t, n.Peers(), addrBalance)
// send value message randomly // send value message randomly
tests.SendValueMessagesOnRandomPeer(t, n.Peers(), addrBalance, 10) randomTxIds := tests.SendValueMessagesOnRandomPeer(t, n.Peers(), addrBalance, 10)
txIds = append(txIds, randomTxIds...)
// wait for messages to be gossiped // wait for messages to be gossiped
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
// check whether all issued messages are available on all nodes // check whether all issued transactions are persistently available on all nodes, and confirmed
tests.CheckBalances(t, n.Peers(), addrBalance, true) tests.CheckTransactions(t, n.Peers(), txIds, true)
// check ledger state
tests.CheckBalances(t, n.Peers(), addrBalance)
// 3. stop all nodes // 3. stop all nodes
for _, peer := range n.Peers() { for _, peer := range n.Peers() {
...@@ -50,6 +57,65 @@ func TestPersistence(t *testing.T) { ...@@ -50,6 +57,65 @@ func TestPersistence(t *testing.T) {
// wait for peers to start // wait for peers to start
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
// 5. check whether all issued messages are persistently available on all nodes // check whether all issued transactions are persistently available on all nodes, and confirmed
tests.CheckBalances(t, n.Peers(), addrBalance, true) tests.CheckTransactions(t, n.Peers(), txIds, true)
// 5. check ledger state
tests.CheckBalances(t, n.Peers(), addrBalance)
}
// TestColoredPersistence issues colored tokens on random peers, restarts them and checks for persistence after restart.
func TestValueColoredPersistence(t *testing.T) {
n, err := f.CreateNetwork("valueColor_TestPersistence", 4, 2)
require.NoError(t, err)
defer tests.ShutdownNetwork(t, n)
// wait for peers to change their state to synchronized
time.Sleep(5 * time.Second)
// master node sends funds to all peers in the network
txIds, addrBalance := tests.SendValueMessagesOnFaucet(t, n.Peers())
// wait for messages to be gossiped
time.Sleep(10 * time.Second)
// check whether the transactions are available on all nodes, and confirmed
tests.CheckTransactions(t, n.Peers(), txIds, true)
// check ledger state
tests.CheckBalances(t, n.Peers(), addrBalance)
// send funds around
randomTxIds := tests.SendColoredValueMessagesOnRandomPeer(t, n.Peers(), addrBalance, 10)
txIds = append(txIds, randomTxIds...)
// wait for value messages to be gossiped
time.Sleep(10 * time.Second)
// check whether all issued transactions are persistently available on all nodes, and confirmed
tests.CheckTransactions(t, n.Peers(), txIds, true)
// check ledger state
tests.CheckBalances(t, n.Peers(), addrBalance)
// stop all nodes
for _, peer := range n.Peers() {
err = peer.Stop()
require.NoError(t, err)
}
// start all nodes
for _, peer := range n.Peers() {
err = peer.Start()
require.NoError(t, err)
}
// wait for peers to start
time.Sleep(10 * time.Second)
// check whether all issued transactions are persistently available on all nodes, and confirmed
tests.CheckTransactions(t, n.Peers(), txIds, true)
// 5. check ledger state
tests.CheckBalances(t, n.Peers(), addrBalance)
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment