func makeMoreBlocks(t *testing.T, mv *Visor, n int, when uint64) []SignedBlock { dest := wallet.NewWalletEntry() blocks := make([]SignedBlock, 0, n) for i := 0; i < n; i++ { tx, err := mv.Spend(mv.Wallets[0].GetID(), wallet.Balance{10 * 1e6, 0}, 0, dest.Address) assert.Nil(t, err) if err != nil { return nil } mv.RecordTxn(tx) assert.Equal(t, len(mv.Unconfirmed.Txns), 1) sb, err := mv.CreateBlock(when + 1 + uint64(i)) assert.Nil(t, err) if err != nil { return nil } err = mv.ExecuteSignedBlock(sb) assert.Nil(t, err) if err != nil { return nil } assert.Equal(t, len(mv.Unconfirmed.Txns), 0) blocks = append(blocks, sb) } return blocks }
func makeValidTxnNoError(t *testing.T, mv *visor.Visor) coin.Transaction { we := wallet.NewWalletEntry() tx, err := mv.Spend(mv.Wallets[0].GetID(), visor.Balance{10 * 1e6, 0}, 0, we.Address) assert.Nil(t, err) return tx }
func makeValidTxnWithFeeFactorAndExtraChange(mv *Visor, factor, extra, change uint64) (coin.Transaction, error) { we := wallet.NewWalletEntry() tmp := mv.Config.CoinHourBurnFactor mv.Config.CoinHourBurnFactor = factor tx, err := mv.Spend(mv.Wallets[0].GetID(), wallet.Balance{10 * 1e6, 1002}, extra, we.Address) mv.Config.CoinHourBurnFactor = tmp return tx, err }
func newDefaultDaemon() *Daemon { cleanupPeers() c := NewConfig() we := wallet.NewWalletEntry() c.Visor.Config.MasterKeys = we c.Visor.Config.GenesisSignature = createGenesisSignature(we) c.Visor.Disabled = true c.DHT.Disabled = true return NewDaemon(c) }
func makeInvalidTxn(mv *Visor) (coin.Transaction, error) { we := wallet.NewWalletEntry() txn, err := mv.Spend(mv.Wallets[0].GetID(), wallet.Balance{10 * 1e6, 0}, 0, we.Address) if err != nil { return txn, err } txn.Out[0].Address = cipher.Address{} return txn, nil }
func setupMasterVisor() VisorConfig { cleanupVisor() coin.SetAddressVersion("test") c := NewVisorConfig() c.Config.IsMaster = true mw := wallet.NewWalletEntry() c.Config.MasterKeys = mw c.Config.GenesisSignature = createGenesisSignature(mw) return c }
func setupMasterVisorConfig() VisorConfig { // Create testmaster.keys file c := NewVisorConfig() c.CoinHourBurnFactor = 0 c.IsMaster = true mw := wallet.NewWalletEntry() c.MasterKeys = mw c.GenesisSignature = createGenesisSignature(mw) return c }
func TestVisorSpend(t *testing.T) { defer cleanupVisor() we := wallet.NewWalletEntry() addr := we.Address vc := newMasterVisorConfig(t) assert.Equal(t, vc.CoinHourBurnFactor, uint64(0)) v := NewVisor(vc) wid := v.Wallets[0].GetFilename() ogb := v.WalletBalance(wid).Confirmed // Test spend 0 amount v = NewVisor(vc) b = wallet.Balance{0, 0} _, err = v.Spend(v.Wallets[0].GetFilename(), b, 0, addr) assert.NotNil(t, err) assert.Equal(t, err.Error(), "Zero spend amount") // Test lacking funds v = NewVisor(vc) b = wallet.Balance{10e16, 10e16} _, err = v.Spend(v.Wallets[0].GetFilename(), b, 10e16, addr) assert.NotNil(t, err) assert.Equal(t, err.Error(), "Not enough coins") // Test created txn too large v = NewVisor(vc) v.Config.MaxBlockSize = 0 b = wallet.Balance{10e6, 10} assert.Panics(t, func() { v.Spend(v.Wallets[0].GetFilename(), b, 0, addr) }) // Test simple spend (we have only 1 address to spend from, no fee) v = NewVisor(vc) assert.Equal(t, v.Config.CoinHourBurnFactor, uint64(0)) b = wallet.Balance{10e6, 10} tx, err := v.Spend(v.Wallets[0].GetFilename(), b, 0, addr) assert.Nil(t, err) assert.Equal(t, len(tx.In), 1) assert.Equal(t, len(tx.Out), 2) // Hash should be updated assert.NotEqual(t, tx.Head.Hash, cipher.SHA256{}) // Should be 1 signature for the single input assert.Equal(t, len(tx.Head.Sigs), 1) // Spent amount should be correct assert.Equal(t, tx.Out[1].Address, addr) assert.Equal(t, tx.Out[1].Coins, b.Coins) assert.Equal(t, tx.Out[1].Hours, b.Hours) // Change amount should be correct ourAddr := v.Wallets[0].GetAddresses()[0] assert.Equal(t, tx.Out[0].Address, ourAddr) assert.Equal(t, tx.Out[0].Coins, ogb.Coins-b.Coins) assert.Equal(t, tx.Out[0].Hours, ogb.Hours-b.Hours) assert.Nil(t, tx.Verify()) }
func TestLoadBlockchainPrivate(t *testing.T) { defer cleanupVisor() cleanupVisor() we := wallet.NewWalletEntry() // No filename should return fresh blockchain bc := loadBlockchain("", we.Address) assert.Equal(t, len(bc.Blocks), 0) // Filename with no file should return fresh blockchain assertFileNotExists(t, testBlockchainFile) bc = loadBlockchain(testBlockchainFile, we.Address) assert.Equal(t, len(bc.Blocks), 0) // Loading an empty blockchain should panic assert.Nil(t, SaveBlockchain(bc, testBlockchainFile)) assertFileExists(t, testBlockchainFile) assert.Panics(t, func() { loadBlockchain(testBlockchainFile, we.Address) }) // Loading a blockchain with a different genesis address should panic vc := newMasterVisorConfig(t) bc.CreateGenesisBlock(vc.MasterKeys.Address, 0, 100e6) assert.Equal(t, len(bc.Blocks), 1) assert.Nil(t, SaveBlockchain(bc, testBlockchainFile)) assertFileExists(t, testBlockchainFile) assert.Panics(t, func() { loadBlockchain(testBlockchainFile, coin.Address{}) }) // Loading a corrupt blockchain should panic corruptFile(t, testBlockchainFile) assert.Panics(t, func() { loadBlockchain(testBlockchainFile, we.Address) }) cleanupVisor() // Loading a valid blockchain should be safe vc = newMasterVisorConfig(t) vc.BlockchainFile = testBlockchainFile v := NewVisor(vc) assert.Nil(t, transferCoinsToSelf(v, v.Config.MasterKeys.Address)) assert.Equal(t, len(v.blockchain.Blocks), 2) assert.Nil(t, v.SaveBlockchain()) assertFileExists(t, testBlockchainFile) bc = loadBlockchain(testBlockchainFile, v.Config.MasterKeys.Address) assert.Equal(t, v.blockchain, bc) }
func TestCreateMasterWallet(t *testing.T) { defer cleanupVisor() cleanupVisor() we := wallet.NewWalletEntry() w := CreateMasterWallet(we) assert.Equal(t, w.NumEntries(), 1) assert.Equal(t, w.GetAddresses()[0], we.Address) // Having a wallet file present should not affect loading master wallet w.Save(testWalletFile) we = wallet.NewWalletEntry() w = CreateMasterWallet(we) assert.Equal(t, w.NumEntries(), 1) assert.Equal(t, w.GetAddresses()[0], we.Address) // Creating with an invalid wallet entry should panic we = wallet.NewWalletEntry() we.Secret = cipher.SecKey{} assert.Panics(t, func() { CreateMasterWallet(we) }) we = wallet.NewWalletEntry() we.Public = cipher.PubKey{} assert.Panics(t, func() { CreateMasterWallet(we) }) }
func addSignedBlockAt(t *testing.T, v *Visor, when uint64) SignedBlock { we := wallet.NewWalletEntry() tx, err := v.Spend(v.Wallets[0].GetFilename(), wallet.Balance{1e6, 0}, 0, we.Address) assert.Nil(t, err) err, known := v.InjectTxn(tx) assert.Nil(t, err) assert.False(t, known) sb, err := v.CreateBlock(when) assert.Nil(t, err) if err != nil { return sb } err = v.ExecuteSignedBlock(sb) assert.Nil(t, err) return sb }
// Returns an appropriate VisorConfig and a master visor func setupVisorConfig() (VisorConfig, *Visor) { // Make a new master visor + blockchain // Get the signed genesis block, mw := wallet.NewWalletEntry() mvc := NewVisorConfig() mvc.CoinHourBurnFactor = 0 mvc.IsMaster = true mvc.MasterKeys = mw mvc.GenesisSignature = createGenesisSignature(mw) mv := NewVisor(mvc) // Use the master values for a client configuration c := NewVisorConfig() c.IsMaster = false c.GenesisSignature = mvc.GenesisSignature c.GenesisTimestamp = mvc.GenesisTimestamp c.MasterKeys = mw c.MasterKeys.Secret = cipher.SecKey{} c.WalletDirectory = testWalletDir return c, mv }
func makeMoreBlocks(mv *visor.Visor, n int, now uint64) ([]visor.SignedBlock, error) { dest := wallet.NewWalletEntry() blocks := make([]visor.SignedBlock, n) for i := 0; i < n; i++ { tx, err := mv.Spend(mv.Wallets[0].GetID(), visor.Balance{10 * 1e6, 0}, 0, dest.Address) if err != nil { return nil, err } mv.RecordTxn(tx) sb, err := mv.CreateBlock(now + uint64(i) + 1) if err != nil { return nil, err } err = mv.ExecuteSignedBlock(sb) if err != nil { return nil, err } blocks[i] = sb } return blocks, nil }
func TestCreateAndPublishBlock(t *testing.T) { defer cleanupVisor() defer gnet.EraseMessages() p, gc := setupPool() vc, mv := setupVisor() dest := wallet.NewWalletEntry() go p.Pool.ConnectionWriteLoop(gc) // Disabled vc.Disabled = true vc.Config = mv.Config v := NewVisor(vc) v.Visor = mv err := v.CreateAndPublishBlock(p) assert.NotNil(t, err) wait() assert.Equal(t, err.Error(), "Visor disabled") assert.Equal(t, len(p.Pool.SendResults), 0) assert.Equal(t, v.Visor.MostRecentBkSeq(), uint64(0)) // Created and sent vc.Disabled = false vc.Config.IsMaster = true vc.Config = mv.Config v = NewVisor(vc) gc.Conn = NewDummyConn(addr) _, err = v.Spend(v.Visor.Wallets[0].GetID(), visor.Balance{10 * 1e6, 0}, 0, dest.Address, p) assert.Nil(t, err) wait() assert.Equal(t, len(p.Pool.SendResults), 1) if len(p.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } <-p.Pool.SendResults err = v.CreateAndPublishBlock(p) wait() assert.Nil(t, err) wait() assert.Equal(t, len(p.Pool.SendResults), 1) if len(p.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr := <-p.Pool.SendResults assert.Nil(t, sr.Error) assert.Equal(t, sr.Connection, gc) _, ok := sr.Message.(*GiveBlocksMessage) assert.True(t, ok) assert.Equal(t, v.Visor.MostRecentBkSeq(), uint64(1)) // Can't create, don't have coins // First, spend all of our coins // vc2, _ := setupVisor() // vc2.Config.GenesisSignature = vc.Config.GenesisSignature // vc2.Config.MasterKeys = vc.Config.MasterKeys // vc2.Config.IsMaster = true // vc2.Disabled = false vc.Config.IsMaster = true vc.Disabled = false v = NewVisor(vc) tx, err := v.Spend(v.Visor.Wallets[0].GetID(), visor.Balance{vc.Config.GenesisCoinVolume, 0}, vc.Config.GenesisCoinVolume, dest.Address, p) mv.RecordTxn(tx) wait() assert.Nil(t, err) assert.Equal(t, len(p.Pool.SendResults), 1) for len(p.Pool.SendResults) > 0 { <-p.Pool.SendResults } err = v.CreateAndPublishBlock(p) assert.Nil(t, err) wait() assert.Equal(t, len(p.Pool.SendResults), 1) for len(p.Pool.SendResults) > 0 { <-p.Pool.SendResults } // No coins to spend, fail assert.Equal(t, v.Visor.MostRecentBkSeq(), uint64(1)) _, err = v.Spend(v.Visor.Wallets[0].GetID(), visor.Balance{10 * 1e6, 0}, 0, dest.Address, p) assert.NotNil(t, err) wait() assert.Equal(t, len(p.Pool.SendResults), 0) err = v.CreateAndPublishBlock(p) assert.NotNil(t, err) wait() assert.Equal(t, len(p.Pool.SendResults), 0) assert.Equal(t, v.Visor.MostRecentBkSeq(), uint64(1)) }
func newWalletEntry(t *testing.T) wallet.WalletEntry { we := wallet.NewWalletEntry() assert.Nil(t, we.Verify()) return we }
func testBlockCreationTicker(t *testing.T, vcfg VisorConfig, master bool, mv *visor.Visor) { vcfg.Config.BlockCreationInterval = 1 defer gnet.EraseMessages() c := NewConfig() c.Visor = vcfg c.Daemon.DisableNetworking = false d := NewDaemon(c) if !master { err := transferCoins(mv, d.Visor.Visor) assert.Nil(t, err) } quit := make(chan int) defer closeDaemon(d, quit) gc := setupExistingPool(d.Pool) go d.Pool.Pool.ConnectionWriteLoop(gc) assert.True(t, gc.LastSent.IsZero()) assert.Equal(t, len(d.Pool.Pool.Pool), 1) assert.Equal(t, d.Pool.Pool.Pool[gc.Id], gc) assert.Equal(t, len(d.Pool.Pool.Addresses), 1) start := 0 if !master { start = 1 } assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(start)) go d.Start(quit) time.Sleep(time.Second + (time.Millisecond * 50)) // Creation should not have occured, because no transaction assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(start)) assert.Equal(t, len(d.Pool.Pool.SendResults), 0) // Creation should occur with a transaction, if not a master // Make a transaction assert.False(t, d.Visor.Config.Disabled) assert.True(t, gc.LastSent.IsZero()) dest := wallet.NewWalletEntry() tx, err := d.Visor.Spend(d.Visor.Visor.Wallets[0].GetID(), visor.Balance{10 * 1e6, 0}, 0, dest.Address, d.Pool) wait() assert.Nil(t, err) assert.Equal(t, d.Pool.Pool.Pool[gc.Id], gc) assert.Equal(t, len(d.Pool.Pool.DisconnectQueue), 0) assert.Equal(t, len(d.Pool.Pool.Pool), 1) assert.Equal(t, len(d.Pool.Pool.Addresses), 1) // Since the daemon loop is running, it will have processed the SendResult // Instead we can check if the txn was announced assert.Equal(t, len(d.Pool.Pool.SendResults), 0) ut := d.Visor.Visor.Unconfirmed.Txns[tx.Hash()] assert.False(t, ut.Announced.IsZero()) assert.False(t, gc.LastSent.IsZero()) ls := gc.LastSent // Now, block should be created time.Sleep(time.Second + (time.Millisecond * 50)) final := start if master { final += 1 } assert.Equal(t, len(d.Pool.Pool.Pool), 1) // Again, we can't check SendResults since the daemon loop is running. // We can only check that LastSent was updated, if its the master and it // created the block. if master { assert.True(t, gc.LastSent.After(ls)) } else { assert.Equal(t, gc.LastSent, ls) } assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(final)) assert.False(t, gc.LastSent.IsZero()) }
func TestExecuteSignedBlock(t *testing.T) { defer cleanupVisor() cleanupVisor() we := wallet.NewWalletEntry() vc := newMasterVisorConfig(t) v := NewVisor(vc) wid := v.Wallets[0].GetFilename() assert.Equal(t, len(v.Unconfirmed.Txns), 0) tx, err := v.Spend(wid, wallet.Balance{1e6, 0}, 0, we.Address) assert.Nil(t, err) err, known := v.InjectTxn(tx) assert.Nil(t, err) assert.False(t, known) assert.Equal(t, len(v.Unconfirmed.Txns), 1) assert.Equal(t, len(v.blockSigs.Sigs), 1) now := uint64(util.UnixNow()) // Invalid signed block sb, err := v.CreateBlock(now) assert.Equal(t, len(v.blockSigs.Sigs), 1) assert.Nil(t, err) sb.Sig = cipher.Sig{} err = v.ExecuteSignedBlock(sb) assert.NotNil(t, err) assert.Equal(t, len(v.Unconfirmed.Txns), 1) assert.Equal(t, len(v.blockSigs.Sigs), 1) // Invalid block sb, err = v.CreateBlock(now) assert.Nil(t, err) // TODO -- empty BodyHash is being accepted, fix blockchain verification sb.Block.Head.BodyHash = cipher.SHA256{} sb.Block.Body.Transactions = make(coin.Transactions, 0) sb = v.SignBlock(sb.Block) err = v.ExecuteSignedBlock(sb) assert.NotNil(t, err) assert.Equal(t, len(v.Unconfirmed.Txns), 1) assert.Equal(t, len(v.blockSigs.Sigs), 1) // Valid block sb, err = v.CreateBlock(now) assert.Nil(t, err) err = v.ExecuteSignedBlock(sb) assert.Nil(t, err) assert.Equal(t, len(v.blockSigs.Sigs), 2) assert.Equal(t, v.blockSigs.Sigs[uint64(1)], sb.Sig) assert.Equal(t, v.blockchain.Blocks[1], sb.Block) assert.Equal(t, len(v.Unconfirmed.Txns), 0) // Test a valid block created by a master but executing in non master vc2, mv := setupVisorConfig() v2 := NewVisor(vc2) w := v2.Wallets[0] addr := w.GetAddresses()[0] tx, err = mv.Spend(mv.Wallets[0].GetFilename(), wallet.Balance{1e6, 0}, 0, addr) assert.Nil(t, err) err, known = mv.InjectTxn(tx) assert.Nil(t, err) assert.False(t, known) sb, err = mv.CreateAndExecuteBlock() assert.Nil(t, err) err = v2.ExecuteSignedBlock(sb) assert.Nil(t, err) assert.Equal(t, len(v2.blockSigs.Sigs), 2) assert.Equal(t, v2.blockSigs.Sigs[uint64(1)], sb.Sig) assert.Equal(t, v2.blockchain.Blocks[1], sb.Block) assert.Equal(t, len(v2.Unconfirmed.Txns), 0) }
func makeValidTxn(mv *visor.Visor) (coin.Transaction, error) { we := wallet.NewWalletEntry() return mv.Spend(mv.Wallets[0].GetID(), visor.Balance{10 * 1e6, 0}, 0, we.Address) }
// Writes a wallet entry to disk at filename func writeMasterKeysFile() (wallet.WalletEntry, error) { we := wallet.NewWalletEntry() rwe := wallet.NewReadableWalletEntry(&we) err := rwe.Save(testMasterKeysFile) return we, err }
func TestNewVisor(t *testing.T) { defer cleanupVisor() // Not master, Invalid master keys cleanupVisor() we := wallet.NewWalletEntry() we.Public = cipher.PubKey{} vc := NewVisorConfig() vc.IsMaster = false assert.Panics(t, func() { NewVisor(vc) }) vc.MasterKeys = we assert.Panics(t, func() { NewVisor(vc) }) // Master, invalid master keys cleanupVisor() vc.IsMaster = true vc.MasterKeys = wallet.WalletEntry{} assert.Panics(t, func() { NewVisor(vc) }) vc.MasterKeys = we assert.Panics(t, func() { NewVisor(vc) }) // Not master, no wallet, blockchain, blocksigs file cleanupVisor() vc = NewVisorConfig() vc.IsMaster = false we, sig, ts := setupGenesis(t) vc.MasterKeys = we vc.GenesisSignature = sig vc.GenesisTimestamp = ts v := NewVisor(vc) assert.Equal(t, len(v.blockchain.Blocks), 1) assert.Equal(t, len(v.blockSigs.Sigs), 1) // Master, no wallet, blockchain, blocksigs file cleanupVisor() vc = NewVisorConfig() we = newWalletEntry(t) vc.MasterKeys = we vc.GenesisSignature = createGenesisSignature(we) vc.IsMaster = true v = NewVisor(vc) assert.Equal(t, len(v.Wallets), 1) // Wallet should only have 1 entry if master assert.Equal(t, v.Wallets[0].NumEntries(), 1) assert.Equal(t, len(v.blockchain.Blocks), 1) assert.Equal(t, len(v.blockSigs.Sigs), 1) // Not master, has all files cleanupVisor() refvc := newGenesisConfig(t) refv := writeVisorFiles(t, refvc) vc = setupChildVisorConfig(refvc, false) v = NewVisor(vc) assert.Equal(t, v.Wallets, refv.Wallets) assert.Equal(t, len(v.Wallets), 1) assert.Equal(t, v.blockchain, refv.blockchain) assert.Equal(t, v.blockSigs, refv.blockSigs) // Master, has all files cleanupVisor() refvc = newMasterVisorConfig(t) refv = writeVisorFiles(t, refvc) vc = setupChildVisorConfig(refvc, true) v = NewVisor(vc) assert.Equal(t, v.Wallets[0].GetEntries(), refv.Wallets[0].GetEntries()) assert.Equal(t, v.blockchain, refv.blockchain) // Not master, wallet is corrupt cleanupVisor() refvc = newGenesisConfig(t) refv = writeVisorFiles(t, refvc) walletFile := filepath.Join(testWalletDir, testWalletFile) assertFileExists(t, walletFile) corruptFile(t, walletFile) vc = setupChildVisorConfig(refvc, false) assert.Panics(t, func() { NewVisor(vc) }) // Master, wallet is corrupt. Nothing happens because master ignores // wallet cleanupVisor() refvc = newMasterVisorConfig(t) refv = writeVisorFiles(t, refvc) assertFileExists(t, walletFile) corruptFile(t, walletFile) vc = setupChildVisorConfig(refvc, true) assert.NotPanics(t, func() { NewVisor(vc) }) // Not master, blocksigs is corrupt cleanupVisor() refvc = newGenesisConfig(t) assertFileNotExists(t, testWalletFile) refv = writeVisorFiles(t, refvc) corruptFile(t, testBlocksigsFile) vc = setupChildVisorConfig(refvc, false) assert.Panics(t, func() { NewVisor(vc) }) // Master, blocksigs is corrupt cleanupVisor() refvc = newMasterVisorConfig(t) refv = writeVisorFiles(t, refvc) corruptFile(t, testBlocksigsFile) assertFileExists(t, testBlocksigsFile) vc = setupChildVisorConfig(refvc, true) assert.Panics(t, func() { NewVisor(vc) }) // Not master, blockchain is corrupt cleanupVisor() refvc = newGenesisConfig(t) refv = writeVisorFiles(t, refvc) corruptFile(t, testBlockchainFile) vc = setupChildVisorConfig(refvc, false) assert.Panics(t, func() { NewVisor(vc) }) // Master, blockchain is corrupt cleanupVisor() refvc = newMasterVisorConfig(t) refv = writeVisorFiles(t, refvc) corruptFile(t, testBlockchainFile) vc = setupChildVisorConfig(refvc, true) assert.Panics(t, func() { NewVisor(vc) }) // Not master, blocksigs is not valid for blockchain cleanupVisor() refvc = newGenesisConfig(t) refv = setupVisorWriting(refvc) // Corrupt the signature refv.blockSigs.Sigs[uint64(0)] = cipher.Sig{} writeVisorFilesDirect(t, refv) vc = setupChildVisorConfig(refvc, false) assert.Panics(t, func() { NewVisor(vc) }) // Master, blocksigs is not valid for blockchain cleanupVisor() refvc = newMasterVisorConfig(t) refv = setupVisorWriting(refvc) // Corrupt the signature refv.blockSigs.Sigs[uint64(0)] = cipher.Sig{} writeVisorFilesDirect(t, refv) vc = setupChildVisorConfig(refvc, true) assert.Panics(t, func() { NewVisor(vc) }) }
func makeValidTxnNoChange(mv *Visor) (coin.Transaction, error) { we := wallet.NewWalletEntry() b := mv.AddressBalance(mv.Config.MasterKeys.Address) return mv.Spend(mv.Wallets[0].GetID(), b.Confirmed, 0, we.Address) }