// Return the instance, properly unmarshaled, given the entry in the database, which is // the hash for the Instance (vv) followed by the source from which to unmarshal (v) func (d *BoltDB) GetInstance(v []byte) fct.IBlock { var vv [32]byte copy(vv[:], v[:32]) v = v[32:] var instance fct.IBlock = d.instances[vv] if instance == nil { vp := fct.NewHash(vv[:]) fct.Prtln("Object hash: ", vp) panic("This should not happen. Object stored in the database has no IBlock instance") } r := instance.GetNewInstance() if r == nil { panic("An IBlock has failed to implement GetNewInstance()") } datalen, v := binary.BigEndian.Uint32(v[0:4]), v[4:] if len(v) != int(datalen) { fct.Prtln("Lengths don't match. Expected ", datalen, " and got ", len(v)) panic("Data not returned properly") } err := r.UnmarshalBinary(v) if err != nil { panic("This should not happen. IBlock failed to unmarshal.") } return r }
func Test_SignTransaction_swcallet(test *testing.T) { w := new(SCWallet) // make me a wallet w.Init() w.NewSeed([]byte("lkdfsgjlagkjlasd")) h0, err := w.GenerateFctAddress([]byte("test 0"), 1, 1) if err != nil { test.Fail() } h1, err := w.GenerateFctAddress([]byte("test 1"), 1, 1) if err != nil { test.Fail() } h2, err := w.GenerateFctAddress([]byte("test 2"), 1, 1) if err != nil { test.Fail() } h3, err := w.GenerateFctAddress([]byte("test 3"), 1, 1) if err != nil { test.Fail() } h4, err := w.GenerateFctAddress([]byte("test 4"), 1, 1) if err != nil { test.Fail() } t := w.CreateTransaction(0) w.AddInput(t, h1, 1000000) w.AddInput(t, h2, 1000000) w.AddOutput(t, h3, 1000000) w.AddOutput(t, h4, 1000000) w.AddInput(t, h0, 0) fee, err := t.CalculateFee(1000) w.UpdateInput(t, 2, h0, fee) signed, err := w.SignInputs(t) if !signed || err != nil { factoid.Prtln("Signed Fail: ", signed, err) test.Fail() } txt, err := t.CustomMarshalText() fct.Prtln(string(txt), "\n ", fee) err = w.ValidateSignatures(t) if err != nil { factoid.Prtln(err) test.Fail() } }
func (fs *Test_state) Init(test *testing.T) { fs.stats.errors = make(map[string]int, 100) fs.stats.full = make(map[string]string, 100) fs.inputAddresses = make([]fct.IAddress, 0, 10) fs.outputAddresses = make([]fct.IAddress, 0, 10) fs.ecoutputAddresses = make([]fct.IAddress, 0, 10) fs.twallet = new(wallet.SCWallet) // Wallet for our tests fs.twallet.Init() for i := 0; i < 10; i++ { addr, err := fs.twallet.GenerateFctAddress([]byte("testin_"+cv.Itoa(i)), 1, 1) if err != nil { fct.Prtln(err) test.Fail() } fs.inputAddresses = append(fs.inputAddresses, addr) fs.outputAddresses = append(fs.outputAddresses, addr) } fs.twallet.NewSeed([]byte("Test State and Balances")) for i := 0; i < 500; i++ { addr, err := fs.twallet.GenerateFctAddress([]byte("testout_"+cv.Itoa(i)), 1, 1) if err != nil { fct.Prtln(err) test.Fail() } fs.outputAddresses = append(fs.outputAddresses, addr) } for i := 0; i < 1000; i++ { addr, err := fs.twallet.GenerateECAddress([]byte("testecout_" + cv.Itoa(i))) if err != nil { fct.Prtln(err) test.Fail() } fs.ecoutputAddresses = append(fs.ecoutputAddresses, addr) } fs.stats.begin() }
// sets up teststate.go func Test_setup_FactoidState(test *testing.T) { // Create a Test State fs = new(Test_state) fs.stats.errors = make(map[string]int, 100) fs.stats.full = make(map[string]string, 100) fs.inputAddresses = make([]fct.IAddress, 0, 10) fs.outputAddresses = make([]fct.IAddress, 0, 10) fs.ecoutputAddresses = make([]fct.IAddress, 0, 10) fs.twallet = new(wallet.SCWallet) // Wallet for our tests fs.twallet.Init() for i := 0; i < 10; i++ { addr, err := fs.twallet.GenerateFctAddress([]byte("testin_"+cv.Itoa(i)), 1, 1) if err != nil { fct.Prtln(err) test.Fail() } fs.inputAddresses = append(fs.inputAddresses, addr) fs.outputAddresses = append(fs.outputAddresses, addr) } for i := 0; i < 500; i++ { addr, err := fs.twallet.GenerateFctAddress([]byte("testout_"+cv.Itoa(i)), 1, 1) if err != nil { fct.Prtln(err) test.Fail() } fs.outputAddresses = append(fs.outputAddresses, addr) } for i := 0; i < 50; i++ { addr, err := fs.twallet.GenerateECAddress([]byte("testecout_" + cv.Itoa(i))) if err != nil { fct.Prtln(err) test.Fail() } fs.ecoutputAddresses = append(fs.outputAddresses, addr) } }
func Test_CreateTransaction_swcallet(test *testing.T) { w := new(SCWallet) // make me a wallet w.Init() w.NewSeed([]byte("lkdfsgjlagkjlasd")) h1, err := w.GenerateFctAddress([]byte("test 1"), 1, 1) if err != nil { test.Fail() } h2, err := w.GenerateFctAddress([]byte("test 2"), 1, 1) if err != nil { test.Fail() } t := w.CreateTransaction(0) w.AddInput(t, h1, 1000000) w.AddOutput(t, h2, 1000000-12000) signed, err := w.SignInputs(t) if !signed || err != nil { factoid.Prtln("Signed Fail: ", signed, err) test.Fail() } fee, err := t.CalculateFee(1000) if fee != 12000 || err != nil { factoid.Prtln("Fee Calculation Failed", fee, err) test.Fail() } err2 := w.Validate(1, t) if err2 != nil { factoid.Prtln(err2) test.Fail() } }
func Test_create_scwallet(test *testing.T) { w := new(SCWallet) // make me a wallet w.Init() w.NewSeed([]byte("lkdfsgjlagkjlasd")) we := new(WalletEntry) rcd := new(factoid.RCD_1) name := "John Smith" pub, pri, err := w.generateKey() if err != nil { factoid.Prtln("Generate Failed") test.Fail() } we.SetRCD(rcd) we.AddKey(pub, pri) we.SetName([]byte(name)) txt, err := we.CustomMarshalText() var _ = txt // factoid.Prtln(string(txt)) }
func Test_create_walletentry(test *testing.T) { w := new(SCWallet) // make me a wallet w.Init() w.NewSeed([]byte("lkdfsgjlagkjlasd")) we := new(WalletEntry) rcd := new(factoid.RCD_1) name := "John Smith" adrtype := "fct" pub, pri, err := w.generateKey() if err != nil { factoid.Prtln("Generate Failed") test.Fail() } we.SetRCD(rcd) we.AddKey(pub, pri) we.SetName([]byte(name)) we.SetType(adrtype) data, err := we.MarshalBinary() if err != nil { test.Fail() } w2 := new(WalletEntry) data, err = w2.UnmarshalBinaryData(data) if err != nil { test.Fail() } if we.IsEqual(w2) != nil { test.Fail() } }
// Run a simulation of Transactions and blocks designed to test a pseudo random transaction set. // If randomize = 0, then we will use the clock to seed the random number generator, and print the // 64 bit seed used. If randomize is set to some value, we use that vaule (allowing us to repeat // tests if we like. func Test_create_genesis_FactoidState(test *testing.T) { randomize := int64(0) numBlocks := 5 numTransactions := 2 // Maximum Transactions maxIn := 1 maxOut := 1 if testing.Short() { fmt.Print("\nDoing Short Tests\n") numBlocks = 5 numTransactions = 20 maxIn = 5 maxOut = 5 } if randomize == 0 { randomize = time.Now().UnixNano() rand.Seed(randomize) randomize = rand.Int63() rand.Seed(randomize) } else { rand.Seed(randomize) } fmt.Println("Randomize Seed Used: ", randomize) cp.CP.AddUpdate( "Test Parms", "status", // Category fmt.Sprintf("Number of Blocks %d Max number Transactions %d", numBlocks, numTransactions), fmt.Sprintf("Randomize Seed: %v", randomize), 0) // Use Bolt DB if !testing.Short() { fs.SetDB(new(database.MapDB)) fs.GetDB().Init() db := stateinit.GetDatabase("./fct_test.db") fs.GetDB().SetPersist(db) fs.GetDB().SetBacker(db) fs.GetDB().DoNotPersist(fct.DB_F_BALANCES) fs.GetDB().DoNotPersist(fct.DB_EC_BALANCES) fs.GetDB().DoNotPersist(fct.DB_BUILD_TRANS) fs.GetDB().DoNotCache(fct.DB_FACTOID_BLOCKS) fs.GetDB().DoNotCache(fct.DB_BAD_TRANS) fs.GetDB().DoNotCache(fct.DB_TRANSACTIONS) } else { fs.SetDB(new(database.MapDB)) fs.GetDB().Init() } // Make the coinbase very generous block.UpdateAmount(10000000) // Set the price for Factoids fs.SetFactoshisPerEC(100000) err := fs.LoadState() if err != nil { fmt.Println("Faid to initialize: ", err) os.Exit(1) } pre := fs.GetTransactionBlock(fs.GetCurrentBlock().GetPrevKeyMR()) if !bytes.Equal(pre.GetHash().Bytes(), fs.GetCurrentBlock().GetPrevKeyMR().Bytes()) { fmt.Printf("Something is ill!") test.Fail() return } // Print the Genesis Block. If we don't know the past, then print it. past := fs.GetTransactionBlock(pre.GetPrevKeyMR()) if past == nil { for _, trans := range pre.GetTransactions() { PrtTrans(trans) } } if err != nil { fct.Prtln("Failed to load:", err) test.Fail() return } var max, min, maxblk int min = 100000 // Create a number of blocks (i) for i := 0; i < numBlocks; i++ { fmt.Println("Block", fs.GetCurrentBlock().GetDBHeight()) PrtTrans(fs.GetCurrentBlock().GetTransactions()[0]) thisRunLimit := (rand.Int() % numTransactions) + 1 cp.CP.AddUpdate( "This Block", "status", // Category fmt.Sprintf("Number of Transactions in this block: %d", thisRunLimit), "", 0) var transCnt int periodMark := 1 // Create a new block for j := fs.stats.transactions; fs.stats.transactions < j+thisRunLimit; { // Execute for some number RECORDED transactions transCnt++ periodvalue := thisRunLimit / 10 if periodvalue == 0 { periodvalue = 1 } if periodMark <= 10 && transCnt%(periodvalue) == 0 { fs.EndOfPeriod(periodMark) periodMark++ } tx := fs.newTransaction(maxIn, maxOut) addtest := true flip := rand.Int() % 100 if rand.Int()%100 < 5 { // Mess up the timestamp on 5 percent of the transactions addtest = false blkts := uint64(fs.GetCurrentBlock().GetCoinbaseTimestamp()) if flip < 49 { // Flip a coin tx.SetMilliTimestamp(blkts - uint64(fct.TRANSACTION_PRIOR_LIMIT) - 1) fs.stats.errors["trans too early"] += 1 fs.stats.full["trans too early"] = "trans too early" } else { tx.SetMilliTimestamp(blkts + uint64(fct.TRANSACTION_POST_LIMIT) + 1) fs.stats.errors["trans too late"] += 1 fs.stats.full["trans too late"] = "trans too late" } fs.twallet.SignInputs(tx) } // Test Marshal/UnMarshal m, err := tx.MarshalBinary() if err != nil { fmt.Println("\n Failed to Marshal: ", err) test.Fail() return } if len(m) > max { max = len(m) cp.CP.AddUpdate( "max transaction size", // tag "info", // Category fmt.Sprintf("Max Transaction Size %d", max), // Title fmt.Sprintf("<pre>#inputs = %-3d #outputs = %-3d #ecoutputs = %-3d<pre>", len(tx.GetInputs()), len(tx.GetOutputs()), len(tx.GetECOutputs())), // Msg 0) // Expire } if len(m) < min { min = len(m) cp.CP.AddUpdate( "min transaction size", // tag "info", // Category fmt.Sprintf("Min Transaction Size %d", min), // Title fmt.Sprintf("<pre>#inputs = %-3d #outputs = %-3d #ecoutputs = %-3d<pre>", len(tx.GetInputs()), len(tx.GetOutputs()), len(tx.GetECOutputs())), // Msg 0) // Expire } k := rand.Int() % (len(m) - 2) k++ good := true flip = rand.Int() % 100 // To simulate bad data, I mess up some of the data here. if rand.Int()%100 < 5 { // Mess up 5 percent of the transactions good = false if flip < 49 { // Flip a coin m = m[k:] fs.stats.errors["lost start of trans"] += 1 fs.stats.full["lost start of trans"] = "lost start of trans" } else { m = m[:k] fs.stats.errors["lost end of trans"] += 1 fs.stats.full["lost end of trans"] = "lost end of trans" } } t := new(fct.Transaction) err = t.UnmarshalBinary(m) if good && tx.IsEqual(t) != nil { fmt.Println("Fail valid Unmarshal") test.Fail() return } if err == nil { if good && err != nil { fmt.Println("Added a transaction that should have failed to be added") fmt.Println(err) test.Fail() return } if !good { fmt.Println("Failed to add a transaction that should have added") test.Fail() return } } if good { err = fs.AddTransaction(j+1, t) } if !addtest && err == nil { ts := int64(t.GetMilliTimestamp()) bts := int64(fs.GetCurrentBlock().GetCoinbaseTimestamp()) fmt.Println("timestamp failure ", ts, bts, ts-bts, fct.TRANSACTION_POST_LIMIT) test.Fail() return } if !addtest && err == nil { fmt.Println("failed to catch error") test.Fail() return } if addtest && good && err != nil { fmt.Println(err) fmt.Println("Unmarshal Failed. trans is good", "\nand the error detected: ", err, "\nand k:", k, "and flip:", flip) test.Fail() return } if good && addtest { PrtTrans(t) fs.stats.transactions += 1 title := fmt.Sprintf("Bad Transactions: %d Total transaactions %d", fs.stats.badAddresses, fs.stats.transactions) cp.CP.AddUpdate("Bad Transaction", "status", title, "", 0) time.Sleep(time.Second / 100) } else { fs.stats.badAddresses += 1 } } // // Serialization deserialization tests for blocks // blkdata, err := fs.GetCurrentBlock().MarshalBinary() if err != nil { test.Fail() return } blk := fs.GetCurrentBlock().GetNewInstance().(block.IFBlock) err = blk.UnmarshalBinary(blkdata) if err != nil { test.Fail() return } if len(blkdata) > maxblk { maxblk = len(blkdata) cp.CP.AddUpdate( "maxblocksize", // tag "info", // Category fmt.Sprintf("Max Block Size: %dK", maxblk/1024), // Title "", // Msg 0) // Expires } sec1 := fs.stats.TransactionsPerSec() sec2 := fs.stats.TotalTransactionsPerSec() cp.CP.AddUpdate( "transpersec", // tag "info", // Category fmt.Sprintf("Transactions per second %4.2f, (+ bad) %4.2f", sec1, sec2), // Title "", // Msg 0) // Expires fmt.Println("Block Check") blk1 := fs.GetCurrentBlock() blk1MR := fs.GetCurrentBlock().GetHash() fmt.Println("ProcessEndOfBlock") fs.ProcessEndOfBlock() // Process the block. fmt.Println("Check ProcessEndOfBlock") blk2PMR := fs.GetCurrentBlock().GetPrevKeyMR() if !bytes.Equal(blk1MR.Bytes(), blk2PMR.Bytes()) { fmt.Println("MR's don't match") test.Fail() return } data, err := blk1.MarshalBinary() if err != nil { fmt.Println("Failed to Marshal") test.Fail() return } blk1b := new(block.FBlock) err = blk1b.UnmarshalBinary(data) if err != nil { fmt.Println("Failed to Unmarshal") test.Fail() return } if !bytes.Equal(blk2PMR.Bytes(), blk1b.GetKeyMR().Bytes()) { fmt.Println("Unmarshaled MR doesn't match") test.Fail() return } c := 1 keys := make([]string, 0, len(fs.stats.errors)) for k := range fs.stats.errors { keys = append(keys, k) } for i := 0; i < len(keys)-1; i++ { for j := 0; j < len(keys)-i-1; j++ { if keys[j] < keys[j+1] { t := keys[j] keys[j] = keys[j+1] keys[j+1] = t } } } var out bytes.Buffer for _, key := range keys { ecnt := fs.stats.errors[key] by := []byte(fs.stats.full[key]) prt := string(by) if len(prt) > 80 { prt = string(by[:80]) + "..." } prt = strings.Replace(prt, "\n", " ", -1) out.WriteString(fmt.Sprintf("%6d %s\n", ecnt, prt)) c++ } cp.CP.AddUpdate( "transerrors", // tag "errors", // Category "Transaction Errors Detected:", // Title "<pre>"+string(out.Bytes())+"</pre>", // Msg 0) // Expires } fmt.Println("\nDone") // // Get the head of the Factoid Chain // blk := fs.GetTransactionBlock(fct.FACTOID_CHAINID_HASH) // hashes := make([]fct.IHash,0,10) // // First run back from the head back to the genesis block, collecting hashes. // for { // h := blk.GetHash() // hashes = append(hashes,h) // if bytes.Compare(blk.GetPrevKeyMR().Bytes(),fct.ZERO) == 0 { // break // } // tblk := fs.GetTransactionBlock(blk.GetPrevKeyMR()) // blk = tblk // time.Sleep(time.Second/100) // } // // // Now run forward, and build our accounting // for i := len(hashes)-1; i>=0; i-- { // blk = fs.GetTransactionBlock(hashes[i]) // fmt.Println("Block",blk.GetDBHeight()) // for _,trans := range blk.GetTransactions() { // PrtTrans(trans) // } // } }
func (fs *Test_state) newTransaction(maxIn, maxOut int) fct.ITransaction { var max, sum uint64 fs.inputAddresses = make([]fct.IAddress, 0, 20) for _, output := range fs.outputAddresses { bal := fs.GetBalance(output) if bal > 10000000 { fs.inputAddresses = append(fs.inputAddresses, output) sum += bal } if max < bal { max = bal } } cp.CP.AddUpdate( "Test max min inputs", // tag "info", // Category "Tests generation", // Title fmt.Sprintf("Input Addresses %d\nMax balance %s, Average Balance %s", len(fs.inputAddresses), strings.TrimSpace(fct.ConvertDecimal(max)), strings.TrimSpace(fct.ConvertDecimal(sum/uint64(len(fs.inputAddresses))))), // Msg 60) // Expire // The following code is a function that creates an array // of addresses pulled from some source array of addresses // selected randomly. var makeList = func(source []fct.IAddress, cnt int) []fct.IAddress { adrs := make([]fct.IAddress, 0, cnt) for len(adrs) < cnt { i := rand.Int() % len(source) adr := source[i] adrs = append(adrs, adr) } return adrs } mIn := maxIn mOut := maxOut mEc := maxOut // Distribute our randomness over various spaces. This doesn't // make for realistic transactions, but we don't care so much. joker := rand.Int() % 100 if joker < 1 { mIn = maxIn * 2 } if joker < 2 { mIn = maxIn * 4 } if joker < 3 { mIn = maxIn * 8 } if joker < 4 { mIn = maxIn * 16 } if joker < 5 { mIn = maxIn * 32 } if joker < 6 { mIn = maxIn * 64 } joker = rand.Int() % 100 if joker < 1 { mOut = maxOut * 2 } if joker < 2 { mOut = maxOut * 4 } if joker < 3 { mOut = maxOut * 8 } if joker < 4 { mOut = maxOut * 16 } if joker < 5 { mOut = maxOut * 32 } if joker < 6 { mOut = maxOut * 64 } joker = rand.Int() % 100 if joker < 1 { mEc = maxOut * 2 } if joker < 2 { mEc = maxOut * 4 } if joker < 3 { mEc = maxOut * 8 } if joker < 4 { mEc = maxOut * 16 } if joker < 5 { mEc = maxOut * 32 } if joker < 6 { mEc = maxOut * 64 } // Get one to five inputs, and one to five outputs numInputs := rand.Int()%mIn + 1 numOutputs := rand.Int() % mOut mumECOutputs := rand.Int() % mEc numInputs = (numInputs % (len(fs.inputAddresses) - 2)) + 1 // fmt.Println("inputs outputs",numInputs,numOutputs, "limits",len(fs.inputAddresses),len(fs.outputAddresses)) // Get my input and output addresses inputs := makeList(fs.inputAddresses, numInputs) outputs := makeList(fs.outputAddresses, numOutputs) ecoutputs := makeList(fs.ecoutputAddresses, mumECOutputs) var paid uint64 t := fs.twallet.CreateTransaction(fs.GetTimeMilli()) for _, adr := range inputs { balance := fs.GetBalance(adr) toPay := uint64(rand.Int63()) % (balance / 2) paid = toPay + paid fs.twallet.AddInput(t, adr, toPay) } paid = paid - fs.GetFactoshisPerEC()*uint64(len(ecoutputs)) for _, adr := range outputs { fs.twallet.AddOutput(t, adr, paid/uint64(len(outputs))) } for _, adr := range ecoutputs { fs.twallet.AddECOutput(t, adr, fs.GetFactoshisPerEC()) } fee, _ := t.CalculateFee(fs.GetFactoshisPerEC()) toPay := t.GetInputs()[0].GetAmount() fs.twallet.UpdateInput(t, 0, inputs[0], toPay+fee) valid, err1 := fs.twallet.SignInputs(t) if err1 != nil { fct.Prtln("Failed to sign transaction") } if !valid { fct.Prtln("Transaction is not valid") } if err := fs.Validate(len(fs.GetCurrentBlock().GetTransactions()), t); err != nil || err1 != nil { fs.GetDB().Put(fct.DB_BAD_TRANS, t.GetHash(), t) fs.stats.badAddresses += 1 str := []byte(err.Error())[:10] if bytes.Compare(str, []byte("The inputs")) != 0 { str = []byte(err.Error())[:30] } fs.stats.errors[string(str)] += 1 fs.stats.full[string(str)] = err.Error() return fs.newTransaction(maxIn, maxOut) } return t }
func (fs *Test_state) newTransaction() fct.ITransaction { var maxBal, sum uint64 fs.inputAddresses = make([]fct.IAddress, 0, 20) for _, output := range fs.outputAddresses { bal := fs.GetBalance(output) if bal > 100000000 { fs.inputAddresses = append(fs.inputAddresses, output) sum += bal } if maxBal < bal { maxBal = bal } } avgBal := sum / uint64(len(fs.inputAddresses)) if fs.stats.transactions == 0 { fs.stats.MaxBal = maxBal fs.stats.AvgBal = avgBal } else { fs.stats.MaxBal = (fs.stats.MaxBal*uint64(fs.stats.transactions) + maxBal) / uint64(fs.stats.transactions+1) fs.stats.AvgBal = (fs.stats.AvgBal*uint64(fs.stats.transactions) + avgBal) / uint64(fs.stats.transactions+1) } cp.CP.AddUpdate( "Test max min inputs", // tag "info", // Category "Tests generation", // Title fmt.Sprintf("Input Addresses %d\n"+ "Total Max balance %15s, Average Balance %15s\n"+ "Last Max balance %15s, Average Balance %16s", len(fs.inputAddresses), strings.TrimSpace(fct.ConvertDecimal(fs.stats.MaxBal)), strings.TrimSpace(fct.ConvertDecimal(fs.stats.AvgBal)), strings.TrimSpace(fct.ConvertDecimal(maxBal)), strings.TrimSpace(fct.ConvertDecimal(avgBal))), // Msg 0) // Expire // The following code is a function that creates an array // of addresses pulled from some source array of addresses // selected randomly. var makeList = func(source []fct.IAddress, cnt int) []fct.IAddress { adrs := make([]fct.IAddress, 0, cnt) for len(adrs) < cnt { var i int if len(source) == 0 { return adrs } i = rand.Int() % len(source) adr := source[i] adrs = append(adrs, adr) } return adrs } // Get one to five inputs, and one to five outputs numInputs := fs.getRnd() numOutputs := fs.getRnd() mumECOutputs := fs.getRnd() if avgBal > 10000000000 { numOutputs = 0 } // Throw away Factoids if too much money in the system lim := len(fs.inputAddresses) - 2 if lim <= 0 { lim = 1 } numInputs = (numInputs % (lim)) + 1 // fmt.Println("inputs outputs",numInputs,numOutputs, "limits",len(fs.inputAddresses),len(fs.outputAddresses)) // Get my input and output addresses inputs := makeList(fs.inputAddresses, numInputs) outputs := makeList(fs.outputAddresses, numOutputs) ecoutputs := makeList(fs.ecoutputAddresses, mumECOutputs) var paid uint64 t := fs.twallet.CreateTransaction(fs.GetTimeMilli()) for _, adr := range inputs { balance := fs.GetBalance(adr) toPay := uint64(rand.Int63()) % (balance / 2) paid = toPay + paid fs.twallet.AddInput(t, adr, toPay) } paid = paid - fs.GetFactoshisPerEC()*uint64(len(ecoutputs)) for _, adr := range outputs { fs.twallet.AddOutput(t, adr, paid/uint64(len(outputs))) } for _, adr := range ecoutputs { fs.twallet.AddECOutput(t, adr, fs.GetFactoshisPerEC()) } fee, _ := t.CalculateFee(fs.GetFactoshisPerEC()) toPay := t.GetInputs()[0].GetAmount() fs.twallet.UpdateInput(t, 0, inputs[0], toPay+fee) valid, err1 := fs.twallet.SignInputs(t) if err1 != nil { fct.Prtln("Failed to sign transaction") } if !valid { fct.Prtln("Transaction is not valid") } if err := fs.Validate(len(fs.GetCurrentBlock().GetTransactions()), t); err != nil || err1 != nil { fs.GetDB().Put(fct.DB_BAD_TRANS, t.GetHash(), t) fs.stats.badAddresses += 1 str := []byte(err.Error())[:10] if bytes.Compare(str, []byte("The inputs")) != 0 { str = []byte(err.Error())[:30] } fs.stats.errors[string(str)] += 1 fs.stats.full[string(str)] = err.Error() return fs.newTransaction() } return t }
func Test_create_block(test *testing.T) { w := new(wallet.SCWallet) // make me a wallet w.Init() w.NewSeed([]byte("slfkjasdlfjasflajsfl")) scb := block.NewFBlock(1000, 0) cb := w.CreateTransaction(uint64(time.Now().UnixNano() / 1000000)) scb.AddCoinbase(cb) for i := 0; i < 3; i++ { h0, err := w.GenerateFctAddress([]byte("test "+cv.Itoa(i)+"-0"), 1, 1) if err != nil { sc.Prtln("Error 1") test.Fail() } h1, err := w.GenerateFctAddress([]byte("test "+cv.Itoa(i)+"-1"), 1, 1) if err != nil { sc.Prtln("Error 2") test.Fail() } h2, err := w.GenerateFctAddress([]byte("test "+cv.Itoa(i)+"-2"), 1, 1) if err != nil { sc.Prtln("Error 3") test.Fail() } h3, err := w.GenerateFctAddress([]byte("test "+cv.Itoa(i)+"-3"), 1, 1) if err != nil { sc.Prtln("Error 4") test.Fail() } h4, err := w.GenerateFctAddress([]byte("test "+cv.Itoa(i)+"-4"), 1, 1) if err != nil { sc.Prtln("Error 5") test.Fail() } h5, err := w.GenerateFctAddress([]byte("test "+cv.Itoa(i)+"-5"), 1, 1) if err != nil { sc.Prtln("Error 6") test.Fail() } t := w.CreateTransaction(uint64(time.Now().UnixNano() / 1000000)) w.AddInput(t, h1, 1000000) w.AddInput(t, h2, 1000000) w.AddOutput(t, h3, 1000000) w.AddOutput(t, h4, 500000) w.AddECOutput(t, h5, 500000) w.AddInput(t, h0, 0) fee, err := t.CalculateFee(1000) w.UpdateInput(t, 2, h0, fee) signed, err := w.SignInputs(t) if err != nil { sc.Prtln("Error found: ", err) test.Fail() return } if !signed { sc.Prtln("Not valid") test.Fail() return } err = scb.AddTransaction(t) if err != nil { sc.Prtln("Error found: ", err) test.Fail() return } } data, err := scb.MarshalBinary() if err != nil { fmt.Println(err) test.Fail() return } scb2 := new(block.FBlock) _, err = scb2.UnmarshalBinaryData(data) fmt.Println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", scb2) if err != nil { fmt.Println(err) test.Fail() return } //sc.Prtln("FIRST\n",scb,"SECOND\n",scb2) if scb.IsEqual(scb2) != nil { fmt.Println(err) test.Fail() return } }
func (fs *FactoidState) LoadState() error { var hashes []fct.IHash cblk := fs.GetTransactionBlock(fct.FACTOID_CHAINID_HASH) // If there is no head for the Factoids in the database, we have an // uninitialized database. We need to add the Genesis Block. TODO if cblk == nil { cp.CP.AddUpdate( "Creating Factoid Genesis Block", // tag "info", // Category "Creating the Factoid Genesis Block", // Title "", // Msg 60) // Expire //gb := block.GetGenesisFBlock(fs.GetTimeMilli(), 1000000,10,200000000000) gb := block.GetGenesisFBlock() fs.PutTransactionBlock(gb.GetHash(), gb) fs.PutTransactionBlock(fct.FACTOID_CHAINID_HASH, gb) err := fs.AddTransactionBlock(gb) if err != nil { fct.Prtln("Failed to build initial state.\n", err) return err } fs.ProcessEndOfBlock() return nil } blk := cblk // First run back from the head back to the genesis block, collecting hashes. for { if blk == nil { return fmt.Errorf("Block not found or not formated properly") } h := blk.GetHash() for _, hash := range hashes { if bytes.Compare(hash.Bytes(), h.Bytes()) == 0 { return fmt.Errorf("Corrupted database; same hash found twice") } } hashes = append(hashes, h) if bytes.Compare(blk.GetPrevKeyMR().Bytes(), fct.ZERO_HASH) == 0 { break } tblk := fs.GetTransactionBlock(blk.GetPrevKeyMR()) if tblk == nil { return fmt.Errorf("Failed to find the block at height: %d", blk.GetDBHeight()-1) } if !bytes.Equal(tblk.GetHash().Bytes(), blk.GetPrevKeyMR().Bytes()) { return fmt.Errorf("Hash Failure! Database must be rebuilt") } blk = tblk time.Sleep(time.Second / 100) cp.CP.AddUpdate( "loadState", "status", // Category "Loading State", fmt.Sprintf("Scanning backwards. Block: %d", blk.GetDBHeight()), 0) } // Now run forward, and build our accounting for i := len(hashes) - 1; i >= 0; i-- { blk = fs.GetTransactionBlock(hashes[i]) if blk == nil { return fmt.Errorf("Should never happen. Block not found in the Database\n"+ "No block found for: %s", hashes[i].String()) } err := fs.AddTransactionBlock(blk) // updates accounting for this block if err != nil { fct.Prtln("Failed to rebuild state.\n", err) return err } time.Sleep(time.Second / 100) cp.CP.AddUpdate( "loadState", "status", // Category "Loading State", fmt.Sprintf("Loading and Processing. Block: %d", blk.GetDBHeight()), 0) } fs.dbheight = blk.GetDBHeight() fs.ProcessEndOfBlock() return nil }
func Test_create_genesis_FactoidState(test *testing.T) { fmt.Print("\033[2J") numBlocks := 5000 numTransactions := 500 maxIn := 5 maxOut := 20 if testing.Short() { fmt.Print("\nDoing Short Tests\n") numBlocks = 5 numTransactions = 20 maxIn = 5 maxOut = 5 } // Use Bolt DB if !testing.Short() { fs.SetDB(new(database.MapDB)) fs.GetDB().Init() db := stateinit.GetDatabase("/tmp/fct_test.db") fs.GetDB().SetPersist(db) fs.GetDB().SetBacker(db) fs.GetDB().DoNotPersist(fct.DB_F_BALANCES) fs.GetDB().DoNotPersist(fct.DB_EC_BALANCES) fs.GetDB().DoNotPersist(fct.DB_BUILD_TRANS) fs.GetDB().DoNotCache(fct.DB_FACTOID_BLOCKS) fs.GetDB().DoNotCache(fct.DB_BAD_TRANS) fs.GetDB().DoNotCache(fct.DB_TRANSACTIONS) } else { fs.SetDB(new(database.MapDB)) fs.GetDB().Init() } // Set the price for Factoids fs.SetFactoshisPerEC(100000) err := fs.LoadState() if err != nil { fct.Prtln("Failed to load:", err) test.Fail() return } fs.ProcessEndOfBlock() // Make the coinbase very generous block.UpdateAmount(100000000000) var cnt, max, min, maxblk int min = 100000 // Create a number of blocks (i) for i := 0; i < numBlocks; i++ { periodMark := 1 // Create a new block for j := cnt; cnt < j+numTransactions; { // Execute for some number RECORDED transactions if periodMark <= 10 && cnt%(numTransactions/10) == 0 { fs.EndOfPeriod(periodMark) periodMark++ } tx := fs.newTransaction(maxIn, maxOut) addtest := true flip := rand.Int() % 100 if rand.Int()%100 < 5 { // Mess up the timestamp on 5 percent of the transactions addtest = false blkts := uint64(fs.GetCurrentBlock().GetCoinbaseTimestamp()) if flip < 49 { // Flip a coin tx.SetMilliTimestamp(blkts - uint64(fct.TRANSACTION_PRIOR_LIMIT) - 1) fs.stats.errors["trans too early"] += 1 fs.stats.full["trans too early"] = "trans too early" } else { tx.SetMilliTimestamp(blkts + uint64(fct.TRANSACTION_POST_LIMIT) + 1) fs.stats.errors["trans too late"] += 1 fs.stats.full["trans too late"] = "trans too late" } fs.twallet.SignInputs(tx) } // Test Marshal/UnMarshal m, err := tx.MarshalBinary() if err != nil { fmt.Println("\n Failed to Marshal: ", err) test.Fail() return } if len(m) > max { fmt.Print("\033[33;0H") max = len(m) fmt.Println("Max Transaction", cnt, "is", len(m), "Bytes long. ", len(tx.GetInputs()), "inputs and", len(tx.GetOutputs()), "outputs and", len(tx.GetECOutputs()), "ecoutputs ") fmt.Print("\033[41;0H") } if len(m) < min { fmt.Print("\033[34;0H") min = len(m) fmt.Println("Min Transaction", cnt, "is", len(m), "Bytes long. ", len(tx.GetInputs()), "inputs and", len(tx.GetOutputs()), "outputs and", len(tx.GetECOutputs()), "ecoutputs ") fmt.Print("\033[41;0H") } k := rand.Int() % (len(m) - 2) k++ good := true flip = rand.Int() % 100 // To simulate bad data, I mess up some of the data here. if rand.Int()%100 < 5 { // Mess up 5 percent of the transactions good = false if flip < 49 { // Flip a coin m = m[k:] fs.stats.errors["lost start of trans"] += 1 fs.stats.full["lost start of trans"] = "lost start of trans" } else { m = m[:k] fs.stats.errors["lost end of trans"] += 1 fs.stats.full["lost end of trans"] = "lost end of trans" } } t := new(fct.Transaction) err = t.UnmarshalBinary(m) if good && tx.IsEqual(t) != nil { fmt.Println("\n\n\n\n\n\nFail valid Unmarshal") test.Fail() return } if err == nil { if good && err != nil { fmt.Println("\n\n\n\n\n\n\nAdded a transaction that should have failed to be added") fmt.Println(err) test.Fail() return } if !good { fmt.Println("\n\n\n\n\n\n\nFailed to add a transaction that should have added") test.Fail() return } } if good { err = fs.AddTransaction(t) } if !addtest && err == nil { ts := int64(t.GetMilliTimestamp()) bts := int64(fs.GetCurrentBlock().GetCoinbaseTimestamp()) fmt.Println("\n\n\n\n\n\n\ntimestamp failure ", ts, bts, ts-bts, fct.TRANSACTION_POST_LIMIT) test.Fail() return } if !addtest && err == nil { fmt.Println("\n\n\n\n\n\n\nfailed to catch error") test.Fail() return } if addtest && good && err != nil { fmt.Println(err) fmt.Println("\n\n\n\n\n\n\n\n\n\nUnmarshal Failed. trans is good", "\nand the error detected: ", err, "\nand k:", k, "and flip:", flip) test.Fail() return } if good && addtest { fmt.Print("\033[32;0H") fmt.Println("Bad Transactions: ", fs.stats.badAddresses, " Total transactions: ", cnt, "\r") fmt.Print("\033[42;0H") time.Sleep(9000) cnt += 1 } else { fs.stats.badAddresses += 1 } } // // Serialization deserialization tests for blocks // blkdata, err := fs.GetCurrentBlock().MarshalBinary() if err != nil { test.Fail() return } blk := fs.GetCurrentBlock().GetNewInstance().(block.IFBlock) err = blk.UnmarshalBinary(blkdata) if err != nil { test.Fail() return } if len(blkdata) > maxblk { fmt.Printf("\033[%d;%dH", (blk.GetDBHeight())%30+1, (((blk.GetDBHeight())/30)%1)*25+1) fmt.Printf("Blk:%6d %8d B ", blk.GetDBHeight(), len(blkdata)) fmt.Printf("\033[%d;%dH", (blk.GetDBHeight())%30+2, (((blk.GetDBHeight())/30)%1)*25+1) fmt.Printf("%24s", "===================== ") } // blk:=fs.GetCurrentBlock() // Get Current block, but hashes are set by processing. fs.ProcessEndOfBlock() // Process the block. // fmt.Println(blk) // Now print it. c := 1 keys := make([]string, 0, len(fs.stats.errors)) for k := range fs.stats.errors { keys = append(keys, k) } for i := 0; i < len(keys)-1; i++ { for j := 0; j < len(keys)-i-1; j++ { if keys[j] < keys[j+1] { t := keys[j] keys[j] = keys[j+1] keys[j+1] = t } } } for _, key := range keys { cnt := fs.stats.errors[key] by := []byte(fs.stats.full[key]) prt := string(by) if len(prt) > 80 { prt = string(by[:80]) + "..." } prt = strings.Replace(prt, "\n", " ", -1) fmt.Printf("\033[%d;30H %5d %-83s", c, cnt, prt) c++ } } fmt.Println("\nDone") }
func (fs *Test_state) newTransaction(maxIn, maxOut int) fct.ITransaction { var max, max2 uint64 fs.inputAddresses = make([]fct.IAddress, 0, 20) for _, output := range fs.outputAddresses { bal := fs.GetBalance(output) if bal > 100000 { fs.inputAddresses = append(fs.inputAddresses, output) } if max < bal { max2 = max max = bal } else { if max2 < bal { max2 = bal } } } // The following code is a function that creates an array // of addresses pulled from some source array of addresses // selected randomly. var makeList = func(source []fct.IAddress, cnt int) []fct.IAddress { adrs := make([]fct.IAddress, 0, cnt) for len(adrs) < cnt { i := rand.Int() % len(source) adr := source[i] adrs = append(adrs, adr) } return adrs } mIn := maxIn mOut := maxOut joker := rand.Int() % 100 if joker < 1 { mIn = maxIn * 100 } joker = rand.Int() % 100 if joker < 1 { mOut = maxOut * 200 } // Get one to five inputs, and one to five outputs numInputs := rand.Int()%mIn + 1 numOutputs := rand.Int() % mOut mumECOutputs := rand.Int() % mOut numInputs = (numInputs % (len(fs.inputAddresses) - 2)) + 1 // fmt.Println("inputs outputs",numInputs,numOutputs, "limits",len(fs.inputAddresses),len(fs.outputAddresses)) // Get my input and output addresses inputs := makeList(fs.inputAddresses, numInputs) outputs := makeList(fs.outputAddresses, numOutputs) ecoutputs := makeList(fs.ecoutputAddresses, mumECOutputs) var paid uint64 t := fs.twallet.CreateTransaction(fs.GetTimeMilli()) for _, adr := range inputs { balance := fs.GetBalance(adr) toPay := uint64(rand.Int63()) % (balance) paid = toPay + paid fs.twallet.AddInput(t, adr, toPay) //fmt.Print("\033[10;3H") //fmt.Printf("%s %s \n",adr.String(),fct.ConvertDecimal(toPay)) //fmt.Print("\033[40;3H") } paid = paid - fs.GetFactoshisPerEC()*uint64(len(ecoutputs)) for _, adr := range outputs { fs.twallet.AddOutput(t, adr, paid/uint64(len(outputs))) } for _, adr := range ecoutputs { fs.twallet.AddECOutput(t, adr, fs.GetFactoshisPerEC()) } fee, _ := t.CalculateFee(fs.GetFactoshisPerEC()) toPay := t.GetInputs()[0].GetAmount() fs.twallet.UpdateInput(t, 0, inputs[0], toPay+fee) valid, err1 := fs.twallet.SignInputs(t) if err1 != nil { fct.Prtln("Failed to sign transaction") } if !valid { fct.Prtln("Transaction is not valid") } if err := fs.Validate(len(fs.GetCurrentBlock().GetTransactions()), t); err != nil || err1 != nil { fs.GetDB().Put(fct.DB_BAD_TRANS, t.GetHash(), t) fs.stats.badAddresses += 1 str := []byte(err.Error())[:10] if bytes.Compare(str, []byte("The inputs")) != 0 { str = []byte(err.Error())[:30] } fs.stats.errors[string(str)] += 1 fs.stats.full[string(str)] = err.Error() return fs.newTransaction(maxIn, maxOut) } return t }