// This is the Baby of Asset tracking! We get the current height of our block // and we go through each entry, unmarshalling it and building a "block". We // then process that block. // // We process transactions in our chain, and maintain a balance of our assets. // func (fs *AssetState) LoadState() error { // First we need to build our list of blocks going back. var blklist []factom.EBlock // Get me a chain head... blkmr, err := factom.GetChainHead(hex.EncodeToString(fs.ChainID())) if err != nil { return err } blk, err := factom.GetEBlock(blkmr.ChainHead) for { if blk.Header.BlockSequenceNumber < fs.nextblockheight { break } blklist = append(blklist, *blk) if blk.Header.BlockSequenceNumber == 0 { break } nblk, err := factom.GetEBlock(blk.Header.PrevKeyMR) if err != nil { fmt.Println("Error Reading Entry blocks") time.Sleep(time.Second) continue } blk = nblk } // Now process blocks forward for i := len(blklist) - 1; i >= 0; i-- { for _, entry := range blklist[i].EntryList { transEntry, err := factom.GetEntry(entry.EntryHash) t := new(fct.Transaction) transdata, err := hex.DecodeString(transEntry.Content) if err != nil { continue } // Ignore bad entries. err = t.UnmarshalBinary(transdata) if err != nil { continue } // Ignore bad entries. fs.AddTransaction(t) } } return nil }
// New Transaction: key -- // We create a new transaction, and track it with the user supplied key. The // user can then use this key to make subsequent calls to add inputs, outputs, // and to sign. Then they can submit the transaction. // // When the transaction is submitted, we clear it from our working memory. // Multiple transactions can be under construction at one time, but they need // their own keys. Once a transaction is either submitted or deleted, the key // can be reused. func (Import) Execute(state IState, args []string) error { if len(args) != 3 { return fmt.Errorf("Invalid Parameters") } key := args[1] filename := args[2] if _, err := os.Stat(filename); err != nil { return fmt.Errorf("Could not find the input file %s", filename) } { // Doing a bit of variable scope management here, since I want t later. t := state.GetFS().GetDB().GetRaw([]byte(fct.DB_BUILD_TRANS), []byte(key)) if t != nil { return fmt.Errorf("That transaction already exists. Specify a new one, or delete this one.") } } data, err := ioutil.ReadFile(filename) var hexdata []byte for _, b := range data { if b > 32 { hexdata = append(hexdata, b) } } bdata, err := hex.DecodeString(string(hexdata)) if err != nil { return err } t := new(fct.Transaction) err = t.UnmarshalBinary(bdata) if err != nil { return err } state.GetFS().GetDB().PutRaw([]byte(fct.DB_BUILD_TRANS), []byte(key), t) fmt.Println("Transaction", filename, "has been imported") return nil }
// This routine generates the Coinbase. This is a fixed amount to be // paid to the federated servers. // // Currently we are paying just a few fixed addresses. // func GetCoinbase(ftime uint64) fct.ITransaction { if false && adrs == nil { var w wallet.ISCWallet w = new(wallet.SCWallet) w.Init() adrs = make([]fct.IAddress, addressCnt) for i := 0; i < addressCnt; i++ { adr, _ := w.GenerateFctAddress([]byte("adr"+string(i)), 1, 1) adrs[i] = adr } } coinbase := new(fct.Transaction) coinbase.SetMilliTimestamp(ftime) for _, adr := range adrs { coinbase.AddOutput(adr, amount) // add specified amount } return coinbase }
// 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) // } // } }
// UnmarshalBinary assumes that the Binary is all good. We do error // out if there isn't enough data, or the transaction is too large. func (b *FBlock) UnmarshalBinaryData(data []byte) (newdata []byte, err error) { // To catch memory errors, I capture the panic and turn it into // a reported error. defer func() { if r := recover(); r != nil { err = fmt.Errorf("Error unmarshalling transaction: %v", r) } }() // To capture the panic, my code needs to be in a function. So I'm // creating one here, and call it at the end of this function. if bytes.Compare(data[:fct.ADDRESS_LENGTH], fct.FACTOID_CHAINID[:]) != 0 { return nil, fmt.Errorf("Block does not begin with the Factoid ChainID") } data = data[32:] b.BodyMR = new(fct.Hash) data, err = b.BodyMR.UnmarshalBinaryData(data) if err != nil { return nil, err } b.PrevKeyMR = new(fct.Hash) data, err = b.PrevKeyMR.UnmarshalBinaryData(data) if err != nil { return nil, err } b.PrevLedgerKeyMR = new(fct.Hash) data, err = b.PrevLedgerKeyMR.UnmarshalBinaryData(data) if err != nil { return nil, err } b.ExchRate, data = binary.BigEndian.Uint64(data[0:8]), data[8:] b.DBHeight, data = binary.BigEndian.Uint32(data[0:4]), data[4:] skip, data := fct.DecodeVarInt(data) // Skip the Expansion Header, if any, since data = data[skip:] // we don't know what to do with it. cnt, data := binary.BigEndian.Uint32(data[0:4]), data[4:] data = data[4:] // Just skip the size... We don't really need it. b.Transactions = make([]fct.ITransaction, cnt, cnt) for i, _ := range b.endOfPeriod { b.endOfPeriod[i] = 0 } var periodMark = 0 for i := uint32(0); i < cnt; i++ { for data[0] == fct.MARKER { b.endOfPeriod[periodMark] = int(i) data = data[1:] periodMark++ } trans := new(fct.Transaction) data, err = trans.UnmarshalBinaryData(data) if err != nil { return nil, fmt.Errorf("Failed to unmarshal a transaction in block.\n" + err.Error()) } b.Transactions[i] = trans } return data, nil }
func (w *SCWallet) CreateTransaction(time uint64) fct.ITransaction { t := new(fct.Transaction) t.SetMilliTimestamp(time) return t }
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") }