protected void Page_Load(object sender, EventArgs e)
        {
            PageAccessRequired       = new Access(CurrentOrganization, AccessAspect.BookkeepingDetails, AccessType.Read);
            this._authenticationData = GetAuthenticationDataAndCulture();

            HotBitcoinAddresses addresses = HotBitcoinAddresses.ForOrganization(_authenticationData.CurrentOrganization);

            foreach (HotBitcoinAddress address in addresses)
            {
                if (address.Chain == BitcoinChain.Core)
                {
                    // These shouldn't exist much, so make sure that we have the equivalent Cash address registered
                    try
                    {
                        HotBitcoinAddress.FromAddress(BitcoinChain.Cash, address.ProtocolLevelAddress);
                    }
                    catch (ArgumentException)
                    {
                        // We didn't have it, so create it
                        BitcoinUtility.TestUnspents(BitcoinChain.Cash, address.ProtocolLevelAddress);
                    }
                }
            }

            Response.ContentType = "application/json";
            Response.Output.WriteLine(FormatJson(addresses));
            Response.End();
        }
        public static AjaxCallResult SetBitcoinPayoutAddress(string bitcoinAddress)
        {
            AuthenticationData authData = GetAuthenticationDataAndCulture();

            if (authData == null)
            {
                throw new UnauthorizedAccessException();
            }

            // Remove whitespace from submitted address (whitespace will probably be entered in some cases)

            bitcoinAddress = bitcoinAddress.Replace(" ", string.Empty);

            // Remove a possible start of "bitcoincash:"

            if (bitcoinAddress.StartsWith("bitcoincash:"))
            {
                bitcoinAddress = bitcoinAddress.Substring("bitcoincash:".Length);
            }

            if (string.IsNullOrEmpty(authData.CurrentUser.BitcoinPayoutAddress))
            {
                if (!BitcoinUtility.IsValidBitcoinAddress(bitcoinAddress))
                {
                    return(new AjaxCallResult {
                        Success = false, DisplayMessage = "Invalid address"
                    });
                }

                authData.CurrentUser.BitcoinPayoutAddress        = bitcoinAddress;
                authData.CurrentUser.BitcoinPayoutAddressTimeSet = DateTime.UtcNow.ToString(CultureInfo.InvariantCulture);

                // TODO: Create notifications for CEO and for user

                NotificationCustomStrings strings = new NotificationCustomStrings();
                strings["BitcoinAddress"] = bitcoinAddress;

                OutboundComm userNotify = OutboundComm.CreateNotification(authData.CurrentOrganization,
                                                                          "BitcoinPayoutAddress_Set", strings, People.FromSingle(authData.CurrentUser));

                strings["ConcernedPersonName"] = authData.CurrentUser.Canonical;

                OutboundComm adminNotify = OutboundComm.CreateNotification(authData.CurrentOrganization,
                                                                           "BitcoinPayoutAddress_Set_OfficerNotify", strings); // will send to admins of org as no people specified

                return(new AjaxCallResult {
                    Success = true
                });
            }
            else
            {
                // If the address is already set

                return(new AjaxCallResult {
                    Success = false, DisplayMessage = "Address already set"
                });
            }
        }
Beispiel #3
0
        public override void Run()
        {
            HotBitcoinAddressUnspent utxoToReturn = HotBitcoinAddressUnspent.FromIdentity(UtxoIdentity);
            HotBitcoinAddress        utxoAddress  = utxoToReturn.Address;
            BitcoinSecret            secretKey    = utxoAddress.PrivateKey;

            // TODO: Verify that the utxoAddress is an EchoTest address, i.e. has second path component == BitcoinUtility.BitcoinEchoTestIndex

            string returnAddress = BitcoinUtility.GetInputAddressesForTransaction(BitcoinChain.Cash, utxoToReturn.TransactionHash)[0]; // assumes at least one input address -- not coinbase

            // Return the money

            BitcoinTransactionInputs inputs = utxoToReturn.AsInputs;
            Int64 satoshisToReturn          = utxoToReturn.AmountSatoshis;

            Coin[]    coins       = inputs.Coins;
            ICoin[]   iCoins      = coins;
            ISecret[] privateKeys = utxoToReturn.AsInputs.PrivateKeys;

            TransactionBuilder txBuilder = new TransactionBuilder();

            txBuilder = txBuilder.SendFees(new Satoshis(BitcoinUtility.EchoFeeSatoshis));
            txBuilder = txBuilder.AddCoins(iCoins);
            txBuilder = txBuilder.AddKeys(privateKeys);

            if (returnAddress.StartsWith("1"))
            {
                txBuilder = txBuilder.Send(new BitcoinPubKeyAddress(returnAddress),
                                           new Satoshis(utxoToReturn.AmountSatoshis - BitcoinUtility.EchoFeeSatoshis));
            }
            else if (returnAddress.StartsWith("3"))
            {
                txBuilder = txBuilder.Send(new BitcoinScriptAddress(returnAddress, Network.Main),
                                           new Satoshis(utxoToReturn.AmountSatoshis - BitcoinUtility.EchoFeeSatoshis));
            }
            else
            {
                throw new ArgumentException("Unrecognized address format");
            }

            Transaction tx = txBuilder.BuildTransaction(true, SigHash.ForkId | SigHash.All);

            BitcoinUtility.BroadcastTransaction(tx, BitcoinChain.Cash);
            utxoToReturn.Delete();
            utxoAddress.UpdateTotal();

            // Update the ledger

            string tx2Description          = "Bitcoin echo test repayment";
            FinancialTransaction ledgerTx2 = FinancialTransaction.Create(this.Organization,
                                                                         DateTime.UtcNow, tx2Description);

            ledgerTx2.AddRow(this.Organization.FinancialAccounts.DebtsOther, satoshisToReturn, this.Person);
            ledgerTx2.AddRow(this.Organization.FinancialAccounts.AssetsBitcoinHot, -satoshisToReturn, this.Person);
            ledgerTx2.BlockchainHash = tx.GetHash().ToString();
        }
Beispiel #4
0
 public void ValidateBitcoinAddressTest()
 {
     Assert.IsTrue(BitcoinUtility.IsValidBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));  // VALID
     Assert.IsTrue(BitcoinUtility.IsValidBitcoinAddress("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"));  // VALID
     Assert.IsTrue(BitcoinUtility.IsValidBitcoinAddress("3KS6AuQbZARSvqnaHoHfL1Xhm3bTLFAzoK"));  // VALID MULTISIG
     Assert.IsFalse(BitcoinUtility.IsValidBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X")); // checksum changed, original data
     Assert.IsFalse(BitcoinUtility.IsValidBitcoinAddress("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // data changed, original checksum
     Assert.IsFalse(BitcoinUtility.IsValidBitcoinAddress("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // invalid chars
     Assert.IsFalse(BitcoinUtility.IsValidBitcoinAddress("BZbvjr"));                             // checksum is fine, address too short
 }
        static public BlockchainTransactionRow FromInsightInfoJson(JObject json, bool inRow = false)
        {
            BlockchainTransactionRow newRow = new BlockchainTransactionRow();

            newRow.Address = (string)json["addr"];

            if (string.IsNullOrEmpty(newRow.Address) && !inRow)
            {
                newRow.Address = (string)json["scriptPubKey"]["addresses"][0];
            }

            if (newRow.Address.StartsWith("bitcoincash:"))  // make sure we're using the same machine readable format
            {
                newRow.Address = BitcoinUtility.EnsureLegacyAddress(newRow.Address);
            }

            string valueSatoshisString = (string)json["valueSat"];

            if (!string.IsNullOrEmpty(valueSatoshisString))
            {
                newRow.ValueSatoshis = Int64.Parse(valueSatoshisString);
            }
            else
            {
                // no valueSat field; we must parse a double without loss of precision

                string valueDoubleString = (string)json["value"];

                int indexOfDecimalPoint = valueDoubleString.IndexOf('.');

                // The length needs to be eight places past the decimal point, so
                // zero-pad on the right side until it is

                while (valueDoubleString.Length <= indexOfDecimalPoint + 8) // less-or-equal is correct here: comparing index and length
                {
                    valueDoubleString += "0";                               // pad to eight decimal places
                }

                // We've now made sure that we have the full eight decimal places, so
                // we can safely remove the decimal point and have an integer string

                valueDoubleString = valueDoubleString.Replace(".", "");

                // Finally, parse as integer string

                newRow.ValueSatoshis = Int64.Parse(valueDoubleString);
            }

            newRow.Index = Int32.Parse((string)json["n"]);
            newRow.Spent = inRow && (bool)(json["spentTxId"] == null? false: true);

            return(newRow);
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            PageAccessRequired       = new Access(CurrentOrganization, AccessAspect.BookkeepingDetails, AccessType.Read);
            this._authenticationData = GetAuthenticationDataAndCulture();

            BitcoinUtility.CheckHotwalletAddresses(_authenticationData.CurrentOrganization);

            HotBitcoinAddresses addresses = HotBitcoinAddresses.ForOrganization(_authenticationData.CurrentOrganization);

            Response.ContentType = "application/json";
            Response.Output.WriteLine(FormatJson(addresses));
            Response.End();
        }
Beispiel #7
0
        private static void OnMondayMorning()
        {
            try
            {
                Dictionary <int, bool> accountTested = new Dictionary <int, bool>();

                // Check the bitcoin hotwallets for forex profit/loss.

                Organizations allOrganizations = Organizations.GetAll();

                foreach (Organization organization in allOrganizations)
                {
                    FinancialAccount hotWalletAccount = organization.FinancialAccounts.AssetsBitcoinHot;

                    if (hotWalletAccount != null)
                    {
                        BitcoinUtility.CheckHotwalletForexProfitLoss(hotWalletAccount);
                        accountTested[hotWalletAccount.Identity] = true;
                    }
                }

                // Detect and log any forex difference exceeding 100 cents.

                FinancialAccounts allAccounts = FinancialAccounts.GetAll(); // across ALL ORGS!

                foreach (FinancialAccount account in allAccounts)
                {
                    // For every account, if it's based on foreign currency, and not already checked,
                    // then check for forex gains/losses

                    if (account.ForeignCurrency != null && !accountTested.ContainsKey(account.Identity))
                    {
                        account.CheckForexProfitLoss();
                    }
                }
            }
            catch (Exception e)
            {
                ExceptionMail.Send(e, true);
                if (testMode)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
Beispiel #8
0
        private static void OnMondayMorning()
        {
            try
            {
                // Detect and log any forex difference exceeding 100 cents.

                FinancialAccounts allAccounts = FinancialAccounts.GetAll(); // across ALL ORGS!

                foreach (FinancialAccount account in allAccounts)
                {
                    // For every account, if it's based on foreign currency, check for forex gains/losses

                    if (account.ForeignCurrency != null)
                    {
                        account.CheckForexProfitLoss();
                    }
                }

                // Also check the bitcoin hotwallets for forex profit/loss as a special case of the above.

                Organizations allOrganizations = Organizations.GetAll();

                foreach (Organization organization in allOrganizations)
                {
                    FinancialAccount hotWalletAccount = organization.FinancialAccounts.AssetsBitcoinHot;

                    if (hotWalletAccount != null)
                    {
                        BitcoinUtility.CheckHotwalletForexProfitLoss(hotWalletAccount);
                    }
                }
            }
            catch (Exception e)
            {
                ExceptionMail.Send(e, true);
                if (testMode)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
        static public AjaxCallResult ProcessTransactionReceived(string guid, string txHash)
        {
            AuthenticationData authData = GetAuthenticationDataAndCulture(); // just to make sure we're called properly
            BitcoinChain       chain    = BitcoinChain.Cash;

            string bitcoinAddress = (string)GuidCache.Get(guid);

            if (BitcoinUtility.TestUnspents(chain, bitcoinAddress))
            {
                HotBitcoinAddressUnspents unspents = HotBitcoinAddress.FromAddress(chain, bitcoinAddress).Unspents;
                Int64 satoshisReceived             = unspents.Last().AmountSatoshis;

                if (unspents.Last().TransactionHash != txHash && txHash.Length > 0)
                {
                    // Race condition.
                    Debugger.Break();
                }

                HotBitcoinAddressUnspent utxoToReturn = unspents.Last();

                Swarmops.Logic.Financial.Money moneyReceived = new Swarmops.Logic.Financial.Money(satoshisReceived,
                                                                                                  Currency.BitcoinCash);

                // Create success message and ledger transaction
                string successMessage = string.Empty;

                // TODO: Get the tx, get the input

                string returnAddress = BitcoinUtility.GetInputAddressesForTransaction(chain, txHash) [0]; // assumes at least one input address

                // Return the money, too. Set fee for a 300-byte transaction.

                ReturnBitcoinEchoUtxoOrder backendOrder = new ReturnBitcoinEchoUtxoOrder(utxoToReturn);
                backendOrder.Create(authData.CurrentOrganization, authData.CurrentUser);

                string tx1Description = "Bitcoin technical echo test (will be repaid immediately)";


                if (authData.CurrentOrganization.Currency.IsBitcoinCash)
                {
                    // The ledger is native bitcoin, so cent units are satoshis

                    FinancialTransaction ledgerTx1 = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                                 DateTime.UtcNow, tx1Description);
                    ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsOther, -(satoshisReceived), authData.CurrentUser);
                    ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, satoshisReceived, authData.CurrentUser);
                    ledgerTx1.BlockchainHash = txHash;

                    // The return payment will be logged when made, so its hash can be recorded

                    if (satoshisReceived % 100 == 0)
                    {
                        successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceivedNative,
                                                       (satoshisReceived / 100.0).ToString("N0"));
                    }
                    else
                    {
                        successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceivedNative,
                                                       (satoshisReceived / 100.0).ToString("N2"));
                    }
                }
                else
                {
                    // The ledger is NOT native bitcoin, so we'll need to convert currencies

                    long orgNativeCents            = moneyReceived.ToCurrency(authData.CurrentOrganization.Currency).Cents;
                    FinancialTransaction ledgerTx1 = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                                 DateTime.UtcNow, tx1Description);
                    ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsOther, -orgNativeCents, authData.CurrentUser);
                    ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, orgNativeCents, authData.CurrentUser).AmountForeignCents = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.BitcoinCash);
                    ledgerTx1.BlockchainHash = txHash;

                    // The second transaction is logged when executed in the back-end order

                    successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceived,
                                                   authData.CurrentOrganization.Currency.DisplayCode, orgNativeCents / 100.0, satoshisReceived / 100.0);
                }

                return(new AjaxCallResult()
                {
                    DisplayMessage = successMessage, Success = true
                });

                // TODO: Ack donation via mail?
                // TODO: Notify CFO/etc of donation?
            }

            return(new AjaxCallResult()
            {
                Success = false
            });
        }
Beispiel #10
0
        private static void OnNoon()
        {
            BotLog.Write(0, "MainCycle", "Noon entry");

            try
            {
                if (!PilotInstallationIds.IsPilot(PilotInstallationIds.PiratePartySE))
                {
                    // PPSE is still running PW4 code for this, so don't run for PPSE

                    Payroll.ProcessMonthly(); // will only actually run on the 1st, but no harm in testing every noon
                }

                // Check all bitcoin accounts for previously-unseen transactions once a day

                Organizations allOrganizations = Organizations.GetAll();
                foreach (Organization organization in allOrganizations)
                {
                    // this actually checks hot storage too, but that's supposed
                    // to be up to date since we're the ones handling it
                    BitcoinUtility.CheckColdStorageForOrganization(organization);
                }

                if (!testMode)
                {
                    /*TestTrace("Running RosterHousekeeping.RemindAllExpiries()...");
                     * RosterHousekeeping.RemindAllExpiries();
                     * TestTrace(" done.\r\n");*/
                }
            }
            catch (Exception e)
            {
                TraceAndReport(e);
            }

            try
            {
                if (!testMode)
                {
                    /*TestTrace("Running SupportDatabase.NotifyBouncingEmails()...");
                     * SupportDatabase.NotifyBouncingEmails();
                     * TestTrace(" done.\r\n");*/
                }
            }
            catch (Exception e)
            {
                TraceAndReport(e);
            }

            try
            {
                /*TestTrace("Running SupportDatabase.CloseDelayWarnings()...");
                 * SupportDatabase.CloseDelayWarnings();
                 * TestTrace(" done.\r\n");*/
            }
            catch (Exception e)
            {
                TraceAndReport(e);
            }

            try
            {
                /*TestTrace("Running SupportMailReview.Run()...");
                 * SupportMailReview.Run();
                 * TestTrace(" done.\r\n");*/
            }
            catch (Exception e)
            {
                TraceAndReport(e);
            }


            BotLog.Write(0, "MainCycle", "Noon exit");
        }
Beispiel #11
0
        private static void Main(string[] args)
        {
            // Are we running yet?

            if (!SystemSettings.DatabaseInitialized)
            {
                // will restart the service every 15s until db initialized on OOBE
                // also, the read of DatabaseInitialized can and will fail if
                // we're not initalized enough to even have a database

                throw new InvalidOperationException();
            }

            // Checking for schemata upgrade first of all, after seeing that db exists

            int startupDbVersion = Database.SwarmDb.DbVersion;

            DatabaseMaintenance.UpgradeSchemata();

            testMode = false;

            SystemSettings.BackendHostname = Dns.GetHostName();


            // Other one-time initializations

            FinancialTransactions.FixAllUnsequenced();
            SupportFunctions.OperatingTopology = OperatingTopology.Backend;

            // Begin main loop

            UnixSignal[] killSignals = null;

            if (!Debugger.IsAttached)
            {
                killSignals = new UnixSignal[] { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM) };
            }

            BotLog.Write(0, "MainCycle", string.Empty);
            BotLog.Write(0, "MainCycle", "-----------------------------------------------");
            BotLog.Write(0, "MainCycle", string.Empty);

            if (args.Length > 0)
            {
                if (args[0].ToLower() == "test")
                {
/*
 *                  BotLog.Write(0, "MainCycle", "Running self-tests");
 *                  HeartBeater.Instance.Beat(heartbeatFile);  // Otherwise Heartbeater.Beat() will fail in various places
 *
 *                  testMode = true;
 *                  Console.WriteLine("Testing All Maintenance Processes (except membership-changing ones).");
 *                  PWLog.Write(PWLogItem.None, 0, PWLogAction.SystemTest, string.Empty, string.Empty);
 *
 *                  Console.WriteLine("\r\n10-second intervals:");
 *                  OnEveryTenSeconds();
 *                  Console.WriteLine("\r\nEvery minute:");
 *                  OnEveryMinute();
 *                  Console.WriteLine("\r\nEvery five minutes:");
 *                  OnEveryFiveMinutes();
 *                  Console.WriteLine("\r\nEvery hour:");
 *                  OnEveryHour();
 *                  Console.WriteLine("\r\nNoon:");
 *                  OnNoon();
 *                  Console.WriteLine("\r\nMidnight:");
 *                  OnMidnight();
 */

                    Console.WriteLine("Testing database access...");

                    Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).Name);
                    Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).PasswordHash);

                    Console.WriteLine("Creating OutboundComm...");

                    OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend);

                    Console.WriteLine("Transmitting...");

                    OutboundComms comms = OutboundComms.GetOpen();

                    Console.WriteLine("{0} open items in outbound comms.", comms.Count);

                    foreach (OutboundComm comm in comms)
                    {
                        if (comm.TransmitterClass != "Swarmops.Utility.Communications.CommsTransmitterMail")
                        {
                            throw new NotImplementedException();
                        }

                        ICommsTransmitter transmitter = new CommsTransmitterMail();

                        OutboundCommRecipients recipients = comm.Recipients;
                        PayloadEnvelope        envelope   = PayloadEnvelope.FromXml(comm.PayloadXml);

                        foreach (OutboundCommRecipient recipient in recipients)
                        {
                            transmitter.Transmit(envelope, recipient.Person);
                        }
                    }


                    Console.Write("\r\nAll tests run. Waiting for mail queue to flush... ");
                    while (!MailTransmitter.CanExit)
                    {
                        Thread.Sleep(50);
                    }

                    Console.WriteLine("done.");
                    BotLog.Write(0, "MainCycle", "Exiting self-tests");
                    return;
                }

                if (args[0].ToLower() == "console")
                {
                    Console.WriteLine("\r\nRunning Swarmops-Backend in CONSOLE mode.\r\n");

                    // -------------------------------------------------------------------------------------
                    // -------------------------------------------------------------------------------------
                    // -------------------------------------------------------------------------------------

                    // -----------------------    INSERT ANY ONE-OFF ACTIONS HERE  -------------------------


                    Console.Write("\r\nWaiting for mail queue to flush... ");

                    while (!MailTransmitter.CanExit)
                    {
                        Thread.Sleep(50);
                    }

                    Console.WriteLine("done.");

                    return;
                }

                if (args[0].ToLowerInvariant() == "pdfregen")
                {
                    if (args.Length > 1)
                    {
                        int docId = Int32.Parse(args[1]);
                        PdfProcessor.Rerasterize(Document.FromIdentity(docId));
                    }
                    else
                    {
                        Console.WriteLine("Regenerating all bitmaps from PDF uploads.");
                        PdfProcessor.RerasterizeAll();
                        Console.WriteLine("Done.");
                    }

                    return;
                }


                if (args[0].ToLower() == "rsm")
                {
                    Console.WriteLine("Testing character encoding: räksmörgås RÄKSMÖRGÅS");
                    return;
                }
            }

            /*
             * MailMessage message = new MailMessage();
             * message.From = new MailAddress(Strings.MailSenderAddress, Strings.MailSenderName);
             * message.To.Add (new MailAddress ("*****@*****.**", "Rick Falkvinge (Piratpartiet)"));
             * message.Subject = "Räksmörgåsarnas ékÖNÖMÏåvdëlnïng";
             * message.Body = "Hejsan hoppsan Räksmörgåsar.";
             * message.BodyEncoding = Encoding.Default;
             * message.SubjectEncoding = Encoding.Default;
             *
             * SmtpClient smtpClient = new SmtpClient ("localhost");
             * smtpClient.Credentials = null; // mono bug
             * smtpClient.Send (message);*/

            Console.WriteLine(" * Swarmops Backend starting");

            BotLog.Write(0, "MainCycle", "Backend STARTING");

            // Disable certificate checking due to Mono not installing with a certificate repository - this is UTTERLY broken

            SupportFunctions.DisableSslCertificateChecks(); // MONO BUG/MISFEATURE: Mono has no root certificates, so can't verify cert

            // Tell sysop we're starting

            OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend);

            // Check for existence of installation ID. If not, create one. Warning: has privacy implications when communicated.

            if (Persistence.Key["SwarmopsInstallationId"] == string.Empty)
            {
                Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString();
            }

            // Check for existence of bitcoin hotwallet root

            BitcoinUtility.VerifyBitcoinHotWallet();

            // Initialize backend socket server

            int backendSocketPort = SystemSettings.WebsocketPortBackend;

            _socketServer = new WebSocketServer(backendSocketPort);
            _socketServer.AddWebSocketService <BackendServices>("/Backend");
            _socketServer.Start();

            // Initialize socket client to Blockchain.Info (pending our own services)

            using (
                _blockChainInfoSocket =
                    new WebSocket("wss://ws.blockchain.info/inv?api_code=" + SystemSettings.BlockchainSwarmopsApiKey))
            {
                // Begin maintenance loop

                DateTime cycleStartTime = DateTime.UtcNow;
                DateTime cycleEndTime;

                int lastSecond = cycleStartTime.Second;
                int lastMinute = cycleStartTime.Minute;
                int lastHour   = cycleStartTime.Hour;

                bool exitFlag = false;

                _blockChainInfoSocket.OnOpen    += new EventHandler(OnBlockchainOpen);
                _blockChainInfoSocket.OnError   += new EventHandler <ErrorEventArgs>(OnBlockchainError);
                _blockChainInfoSocket.OnClose   += new EventHandler <CloseEventArgs>(OnBlockchainClose);
                _blockChainInfoSocket.OnMessage += new EventHandler <MessageEventArgs>(OnBlockchainMessage);

                _blockChainInfoSocket.Connect();

                while (!exitFlag) // exit is handled by signals handling at end of loop
                {
                    BotLog.Write(0, "MainCycle", "Cycle Start");

                    cycleStartTime = DateTime.UtcNow;
                    cycleEndTime   = cycleStartTime.AddSeconds(10);

                    try
                    {
                        OnEveryTenSeconds();

                        if (cycleStartTime.Second < lastSecond)
                        {
                            OnEveryMinute();

                            if (cycleStartTime.Minute % 5 == 0)
                            {
                                OnEveryFiveMinutes();
                            }
                        }

                        if (cycleStartTime.Minute < lastMinute)
                        {
                            OnEveryHour();

                            if (DateTime.Now.Hour == 10 && DateTime.Today.DayOfWeek == DayOfWeek.Tuesday)
                            {
                                OnTuesdayMorning();
                            }

                            if (DateTime.Now.Hour == 7 && DateTime.Today.DayOfWeek == DayOfWeek.Monday)
                            {
                                OnMondayMorning();
                            }
                        }

                        if (cycleStartTime.Hour >= 12 && lastHour < 12)
                        {
                            OnNoon();
                        }

                        if (cycleStartTime.Hour < lastHour)
                        {
                            OnMidnight();
                        }
                    }

                    catch (Exception e)
                    {
                        // Note each "OnEvery..." catches its own errors and sends Exception mails,
                        // so that failure in one should not stop the others from running. This particular
                        // code should never run.

                        ExceptionMail.Send(new Exception("Failed in swarmops-backend main loop", e), true);
                    }

                    lastSecond = cycleStartTime.Second;
                    lastMinute = cycleStartTime.Minute;
                    lastHour   = cycleStartTime.Hour;

                    // Wait for a maximum of ten seconds (the difference between cycleStartTime and cycleEndTime)

                    int      iterationCount = 0;
                    DateTime utcNow         = DateTime.UtcNow;
                    while (utcNow < cycleEndTime && !exitFlag)
                    {
                        int signalIndex = 250;

                        // Handle important service orders (those that can't be lost in a random loss
                        // of connection of a socket):

                        BackendServiceOrders backendOrders = BackendServiceOrders.GetNextBatch(5);
                        backendOrders.Execute(); // takes at most 250ms per BSO reqs

                        // Block until a SIGINT or SIGTERM signal is generated, or 1/4 second has passed.
                        // However, we can't do that in a development environment - it won't have the
                        // Mono.Posix assembly, and won't understand UnixSignals. So people running this in
                        // a dev environment will need to stop it manually.

                        if (!Debugger.IsAttached)
                        {
                            signalIndex = UnixSignal.WaitAny(killSignals, 250);
                        }
                        else
                        {
                            TimeSpan timeLeft = (cycleEndTime - utcNow);

                            BotLog.Write(0, "MainCycle Debug",
                                         string.Format(CultureInfo.InvariantCulture,
                                                       "Waiting for {0:F2} more seconds for cycle end",
                                                       timeLeft.TotalMilliseconds / 1000.0));
                            Thread.Sleep(250);
                        }

                        if (signalIndex < 250)
                        {
                            exitFlag = true;
                            Console.WriteLine("Caught signal " + killSignals[signalIndex].Signum + ", exiting");
                            BotLog.Write(0, "MainCycle",
                                         "EXIT SIGNAL (" + killSignals[signalIndex].Signum + "), terminating backend");
                        }

                        utcNow = DateTime.UtcNow;

                        // Every second, send an internal heartbeat

                        if (iterationCount++ % 4 == 0)
                        {
                            InternalHeartbeat();
                        }
                    }
                }
            }

            Console.WriteLine(" * Swarmops Backend stopping");
            BotLog.Write(0, "MainCycle", "BACKEND EXITING, sending backend-termination notices");

            /*
             * if (HeartBeater.Instance.WasKilled)
             * {
             *  // removed unconditional delete, cron job that restarts bot uses it to know that it is intentionally down.
             *  ExceptionMail.Send(new Exception("HeartBeater triggered restart of Swarmops Backend. Will commence after 800 seconds."), false);
             * }*/

            BotLog.Write(0, "MainCycle", "...done");

            /*
             * while (!MailTransmitter.CanExit)
             * {
             *  System.Threading.Thread.Sleep(50);
             * }*/

            _socketServer.Stop();

            Thread.Sleep(2000);
        }
Beispiel #12
0
        static public AjaxCallResult ProcessTransactionReceived(string guid, string txHash)
        {
            BitcoinChain chain = BitcoinChain.Cash;

            AuthenticationData authData = GetAuthenticationDataAndCulture(); // just to make sure we're called properly

            string bitcoinAddress = (string)GuidCache.Get(guid);

            if (BitcoinUtility.TestUnspents(chain, bitcoinAddress))
            {
                HotBitcoinAddressUnspents unspents = HotBitcoinAddress.FromAddress(chain, bitcoinAddress).Unspents;

                // TODO: Update the HotBitcoinAddress with the new amount?

                HotBitcoinAddressUnspent unspent = null;
                Int64 satoshisReceived           = 0;

                foreach (HotBitcoinAddressUnspent potentialUnspent in unspents)
                {
                    if (potentialUnspent.TransactionHash == txHash)
                    {
                        satoshisReceived = potentialUnspent.AmountSatoshis;
                        unspent          = potentialUnspent;
                    }
                }

                if (unspent == null)  // Supplied transaction hash was not found in collection
                {
                    Debugger.Break(); // TODO: Something else than break the debugger
                }

                Swarmops.Logic.Financial.Money moneyReceived = new Swarmops.Logic.Financial.Money(satoshisReceived,
                                                                                                  Currency.BitcoinCash);

                // Make sure that the hotwallet native currency is bitcoin cash
                authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot.ForeignCurrency = Currency.BitcoinCash;

                // Create success message and ledger transaction
                string successMessage = string.Empty;

                FinancialTransaction testTransaction = null;
                try
                {
                    testTransaction = FinancialTransaction.FromBlockchainHash(authData.CurrentOrganization, txHash);

                    // We've already seen this donation! Something is seriously bogus here
                    Debugger.Break();
                    return(new AjaxCallResult()
                    {
                        DisplayMessage = successMessage, Success = true
                    });
                }
                catch (ArgumentException)
                {
                    // This exception is expected - the transaction should not yet exist
                }

                if (authData.CurrentOrganization.Currency.IsBitcoinCash)
                {
                    // The ledger is native bitcoin cash, so units are Satoshis

                    FinancialTransaction ledgerTx = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                                DateTime.UtcNow, "Donation (bitcoin to hotwallet)");
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.IncomeDonations, -satoshisReceived, authData.CurrentUser);
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, satoshisReceived, authData.CurrentUser);
                    ledgerTx.BlockchainHash = txHash;

                    if (satoshisReceived % 100 == 0)
                    {
                        successMessage = string.Format(Resources.Pages.Financial.Donate_FundsReceivedNative,
                                                       (satoshisReceived / 100.0).ToString("N0"));
                    }
                    else
                    {
                        successMessage = string.Format(Resources.Pages.Financial.Donate_FundsReceivedNative,
                                                       (satoshisReceived / 100.0).ToString("N2"));
                    }
                }
                else
                {
                    // The ledger is NOT native bitcoin, so we'll need to convert currencies

                    long orgNativeCents           = moneyReceived.ToCurrency(authData.CurrentOrganization.Currency).Cents;
                    FinancialTransaction ledgerTx = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                                DateTime.UtcNow, "Donation (bitcoin to hotwallet)");
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.IncomeDonations, -orgNativeCents, authData.CurrentUser);
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, orgNativeCents, authData.CurrentUser).AmountForeignCents = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.BitcoinCash);
                    ledgerTx.BlockchainHash = txHash;

                    successMessage = string.Format(Resources.Pages.Financial.Donate_FundsReceived,
                                                   authData.CurrentOrganization.Currency.DisplayCode, orgNativeCents / 100.0, satoshisReceived / 100.0);
                }

                return(new AjaxCallResult()
                {
                    DisplayMessage = successMessage, Success = true
                });

                // TODO: Ack donation via mail?
                // TODO: Notify CFO/etc of donation?
            }

            return(new AjaxCallResult()
            {
                Success = false
            });
        }
        static public AjaxCallResult CheckTransactionReceived(string guid, string txHash)
        {
            AuthenticationData authData = GetAuthenticationDataAndCulture(); // just to make sure we're called properly

            string bitcoinAddress = (string)GuidCache.Get(guid);

            if (BitcoinUtility.TestUnspents(bitcoinAddress))
            {
                HotBitcoinAddressUnspents unspents = HotBitcoinAddress.FromAddress(bitcoinAddress).Unspents;

                // TODO: Update the HotBitcoinAddress with the new amount?

                Int64 satoshisReceived = unspents.Last().AmountSatoshis;

                if (unspents.Last().TransactionHash != txHash && txHash.Length > 0)
                {
                    // Race condition.
                    Debugger.Break();
                }

                Swarmops.Logic.Financial.Money moneyReceived = new Swarmops.Logic.Financial.Money(satoshisReceived,
                                                                                                  Currency.Bitcoin);

                // Make sure that the hotwallet native currency is bitcoin
                authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot.ForeignCurrency = Currency.Bitcoin;

                // Create success message and ledger transaction
                string successMessage = string.Empty;

                // TODO: Get the tx, get the input

                string returnAddress = BitcoinUtility.GetInputAddressesForTransaction(txHash) [0]; // assumes at least one input address

                if (authData.CurrentOrganization.Currency.IsBitcoin)
                {
                    // The ledger is native bitcoin, so units are Satoshis

                    FinancialTransaction ledgerTx = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                                DateTime.UtcNow, "Bitcoin echo test (will be repaid immediately)");
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsOther, -satoshisReceived, authData.CurrentUser);
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, satoshisReceived, authData.CurrentUser);
                    ledgerTx.BlockchainHash = txHash;

                    if (satoshisReceived % 100 == 0)
                    {
                        successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceivedNative,
                                                       (satoshisReceived / 100.0).ToString("N0"));
                    }
                    else
                    {
                        successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceivedNative,
                                                       (satoshisReceived / 100.0).ToString("N2"));
                    }

                    // TODO: Log the payout back, as an inbound invoice for immediate payout
                }
                else
                {
                    // The ledger is NOT native bitcoin, so we'll need to convert currencies

                    long orgNativeCents           = moneyReceived.ToCurrency(authData.CurrentOrganization.Currency).Cents;
                    FinancialTransaction ledgerTx = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                                DateTime.UtcNow, "Bitcoin echo test (will be repaid immediately)");
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsOther, -orgNativeCents, authData.CurrentUser);
                    ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, orgNativeCents, authData.CurrentUser).AmountForeignCents = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.Bitcoin);
                    ledgerTx.BlockchainHash = txHash;

                    successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceived,
                                                   authData.CurrentOrganization.Currency.DisplayCode, orgNativeCents / 100.0, satoshisReceived / 100.0);

                    // TODO: Create a payout back for this amount -- needs to be specified in bitcoin -- as an inbound invoice
                }

                return(new AjaxCallResult()
                {
                    DisplayMessage = successMessage, Success = true
                });

                // TODO: Ack donation via mail?
                // TODO: Notify CFO/etc of donation?
            }

            return(new AjaxCallResult()
            {
                Success = false
            });
        }
Beispiel #14
0
        static void Main(/*string[] args*/)
        {
            // Establish that we have a database connection

            Person testPerson = Person.FromIdentity(1);

            testPerson.GetSecureAvatarLink(64); // suppress "is never used" warning

            Organization organization = Organization.FromIdentity(7);

            // TODO:

            // 0) Check ForeignCurrency of hotwallet account

            FinancialAccount hotWallet = organization.FinancialAccounts.AssetsBitcoinHot;

            if (hotWallet != null)
            {
                Console.WriteLine("Organization has Hotwallet");

                if (hotWallet.ForeignCurrency != null)
                {
                    if (!hotWallet.ForeignCurrency.IsBitcoinCash)
                    {
                        Console.WriteLine(" - Foreign Currency was incorrect; setting to BCH");

                        hotWallet.ForeignCurrency = Currency.BitcoinCash;
                    }
                }
                else
                {
                    // ForeignCurrency of hotwallet was Null
                    hotWallet.ForeignCurrency = Currency.BitcoinCash;

                    Console.WriteLine(" - Foreign Currency was not set; setting to BCH");
                }
            }

            // 0.5) Re-register the initial Sandbox Echo address

            /*
             * HotBitcoinAddress.Create(organization, BitcoinChain.Cash,
             *               BitcoinUtility.BitcoinEchoTestIndex, 1);*/

            // 1) Check unspents on hotwallet addresses

            /*
             * HotBitcoinAddresses addresses = HotBitcoinAddresses.ForOrganization(organization);
             *
             * foreach (HotBitcoinAddress address in addresses)
             * {
             *  HotBitcoinAddressUnspents unspents1 = HotBitcoinAddressUnspents.ForAddress(address);
             *  int beforeCheckCount = unspents1.Count();
             *
             *  BitcoinUtility.TestUnspents(BitcoinChain.Core, address.ProtocolLevelAddress);
             *  BitcoinUtility.TestUnspents(BitcoinChain.Cash, address.ProtocolLevelAddress);
             *
             *  HotBitcoinAddressUnspents unspents2 = HotBitcoinAddressUnspents.ForAddress(address);
             *  int correctedCount = unspents2.Count();
             *
             *  if (beforeCheckCount != correctedCount)
             *  {
             *      Console.WriteLine(" - Unspent count was corrected: was {0}, changed to {1}", beforeCheckCount, correctedCount);
             *  }
             *
             *  if (
             *      address.DerivationPath.StartsWith(BitcoinUtility.BitcoinEchoTestIndex.ToString() + " "))
             *  {
             *      // This is an address that should be echoed back, all of it
             *
             *      foreach (HotBitcoinAddressUnspent unspent in unspents2)
             *      {
             *          ReturnBitcoinEchoUtxoOrder backendOrder = new ReturnBitcoinEchoUtxoOrder(unspent);
             *          backendOrder.Create(organization, testPerson);
             *      }
             *  }
             * }*/

            // 2) Check cold storage accounts, make sure there are corresponding Cash accounts for all Core accounts

            /*
             * FinancialAccount coldStorageRoot = organization.FinancialAccounts.AssetsBitcoinCold;
             *
             * if (coldStorageRoot != null)
             * {
             *  FinancialAccounts accounts = coldStorageRoot.ThisAndBelow();
             *
             *  foreach (FinancialAccount account in accounts)
             *  {
             *      string bitcoinAddress = account.BitcoinAddress;
             *
             *      if (!String.IsNullOrEmpty(bitcoinAddress))
             *      {
             *          Currency accountCurrency = organization.Currency;
             *          if (account.ForeignCurrency != null)
             *          {
             *              accountCurrency = account.ForeignCurrency;
             *          }
             *
             *          if (accountCurrency.IsBitcoinCore)
             *          {
             *              // Assert there's a corresponding Bitcoin Cash account
             *
             *              bool bitcoinCashExists = false;
             *
             *              FinancialAccounts accountsMatchingAddress =
             *                  FinancialAccounts.FromBitcoinAddress(bitcoinAddress);
             *
             *              foreach (FinancialAccount accountMatchingAddress in accountsMatchingAddress)
             *              {
             *                  if (accountMatchingAddress.Identity == account.Identity)
             *                  {
             *                      continue; // this is the outer loop account we've found in the inner loop
             *                  }
             *
             *                  if (accountMatchingAddress.OrganizationId != account.OrganizationId)
             *                  {
             *                      // This is not supposed to happen, ever, since it implies that two
             *                      // different organizations share the same bitcoin address. Nevertheless
             *                      // it's a theoretically valid case and so we check for it
             *
             *                      continue; // not the right organization
             *                  }
             *
             *                  if (accountMatchingAddress.ForeignCurrency.IsBitcoinCash)
             *                  {
             *                      // We have a match for organization, currency, and address
             *
             *                      bitcoinCashExists = true;
             *                  }
             *              }
             *
             *              if (!bitcoinCashExists)
             *              {
             *                  // Need to create a new Bitcoin Cash address and populate it with transactions,
             *                  // starting on 2017-Dec-30
             *
             *                  if (!account.Name.StartsWith("[Core] "))
             *                  {
             *                      account.Name = "[Core] " + account.Name;
             *                  }
             *
             *                  FinancialAccount correspondingCashAccount = FinancialAccount.Create(
             *                      account.Organization, "[Cash] " + account.Name.Substring(7), account.AccountType,
             *                      account.Parent);
             *
             *                  correspondingCashAccount.BitcoinAddress = account.BitcoinAddress;
             *
             *                  if (!organization.Currency.IsBitcoinCash)
             *                  {
             *                      correspondingCashAccount.ForeignCurrency = Currency.BitcoinCash;
             *                  }
             *              }
             *          }
             *      }
             *  }
             * }*/

            // 2½ - TODO) Shapeshift all Core into Cash

            // 2 3/4 -- Check cold storage for the new Cash accounts

            BitcoinUtility.CheckColdStorageForOrganization(organization);

            // 3) Adjust balances of foreign cents on hotwallet

            // 4) Adjust value of hotwallet
        }