// Create or updates an existing Payment, associated with the given block. // When updating, sets the status to GOOD and sets the block* if not already set. func createOrUpdatePayment(rpcPayment *rpc.RPCPayment, block *Block) *Payment { // SANITY CHECK if block == nil { if rpcPayment.Blockhash != "" || rpcPayment.Blockheight != 0 { panic(NewError("Something is wrong, a rpcPayment with no block should have no hash or height")) } } else { if rpcPayment.Blockhash != block.Hash || rpcPayment.Blockheight != block.Height { panic(NewError("Something is wrong, expected rpcPayment.Blockhash to match block.Hash")) } } // END SANITY CHECK payment := FromRPCPayment(rpcPayment) _, err := SavePayment(db.GetModelDB(), payment) switch db.GetErrorType(err) { case db.ERR_DUPLICATE_ENTRY: UpdatePayment(db.GetModelDB(), payment) default: if err != nil { panic(err) } } return payment }
// This just creates a new row in the accounts_deposits table. // It doesn't actually credit the account, etc. // Must be idempotent. func LoadOrCreateDepositForPayment(payment *bitcoin.Payment) *Deposit { if payment.Id == 0 { panic(NewError("Cannot add deposit for unsaved payment")) } addr := bitcoin.LoadAddress(payment.Address) if addr == nil { panic(NewError("Expected address for payment to deposit")) } deposit := &Deposit{ Type: DEPOSIT_TYPE_CRYPTO, UserId: addr.UserId, Wallet: addr.Wallet, Coin: addr.Coin, Amount: payment.Amount, PaymentId: payment.Id, Status: DEPOSIT_STATUS_PENDING, } _, err := SaveDeposit(db.GetModelDB(), deposit) switch db.GetErrorType(err) { case db.ERR_DUPLICATE_ENTRY: return LoadDepositForPayment(db.GetModelDB(), payment.Id) default: if err != nil { panic(err) } } return deposit }
func LoadMPKByPubKey(pubKey string) *MPK { var mpk MPK err := db.QueryRow( `SELECT `+MPKModel.FieldsSimple+` FROM mpk WHERE pubkey=?`, pubKey, ).Scan(&mpk) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &mpk default: panic(err) } }
func LoadBlockAtHeight(coin string, height uint32) *Block { var block Block err := db.QueryRow( `SELECT `+BlockModel.FieldsSimple+` FROM block WHERE coin=? AND height=? AND (status=0 OR status=1 OR status=10)`, coin, height, ).Scan(&block) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &block default: panic(err) } }
func LoadBlock(hash string) *Block { var block Block err := db.QueryRow( `SELECT `+BlockModel.FieldsSimple+` FROM block WHERE hash=?`, hash, ).Scan(&block) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &block default: panic(err) } }
func LoadMPK(mpkId int64) *MPK { var mpk MPK err := db.QueryRow( `SELECT `+MPKModel.FieldsSimple+` FROM mpk WHERE id=?`, mpkId, ).Scan(&mpk) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &mpk default: panic(err) } }
func SaveOrUpdatePriceLog(tx *db.ModelTx, plog *PriceLog) { var exists int err := tx.QueryRow( `SELECT 1 FROM exchange_price_log WHERE market=? AND interval=? AND time=?`, plog.Market, plog.Interval, plog.Time, ).Scan(&exists) switch db.GetErrorType(err) { case sql.ErrNoRows: SavePriceLog(tx, plog) case nil: UpdatePriceLog(tx, plog) default: panic(err) } }
func Get(key string) string { var value string err := db.QueryRow( `SELECT value FROM kvstore WHERE key_=?`, key, ).Scan(&value) switch db.GetErrorType(err) { case sql.ErrNoRows: return "" case nil: return value default: panic(err) } }
func LoadOrder(id int64) *Order { var order Order err := db.QueryRow( `SELECT `+OrderModel.FieldsSimple+` FROM exchange_order WHERE id=?`, id, ).Scan(&order) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &order default: panic(err) } }
func LoadAddress(address string) *Address { var addr Address err := db.QueryRow( `SELECT `+AddressModel.FieldsSimple+` FROM address WHERE address=?`, address, ).Scan(&addr) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &addr default: panic(err) } }
// Gets the last executed order id, or 0 if none. func LastCompletedOrderId(basisCoin string, coin string) int64 { var lastCompletedOrderId int64 err := db.QueryRow( `SELECT id FROM exchange_order WHERE basis_coin=? AND coin=? AND status=3 ORDER BY id DESC limit 1`, basisCoin, coin, ).Scan(&lastCompletedOrderId) switch db.GetErrorType(err) { case sql.ErrNoRows: return 0 case nil: return lastCompletedOrderId default: panic(err) } }
func LoadLastAddressByWallet(userId int64, wallet string, coin string) *Address { var addr Address err := db.QueryRow( `SELECT `+AddressModel.FieldsSimple+` FROM address WHERE user_id=? AND wallet=? AND coin=? ORDER BY chain_idx DESC LIMIT 1`, userId, wallet, coin, ).Scan(&addr) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &addr default: panic(err) } }
func LoadUserByEmail(email string) *User { var user User err := db.QueryRow( `SELECT `+UserModel.FieldsSimple+` FROM auth_user WHERE email=?`, email, ).Scan( &user, ) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &user default: panic(err) } }
func LoadAPIKey(key string) *APIKey { var apiKey APIKey err := db.QueryRow( `SELECT `+APIKeyModel.FieldsSimple+` FROM auth_api_key WHERE key=?`, key, ).Scan( &apiKey, ) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &apiKey default: panic(err) } }
func LoadUser(userId int64) *User { var user User err := db.QueryRow( `SELECT `+UserModel.FieldsSimple+` FROM auth_user WHERE id=?`, userId, ).Scan( &user, ) switch db.GetErrorType(err) { case sql.ErrNoRows: return nil case nil: return &user default: panic(err) } }
// Keeps trying until one is created in the path. // The resulting address's path will be 'chainpath/x' // where 'x' is the smallest nonnegative integer. func CreateNewAddress(coin string, userId int64, wallet string, mpk *MPK, chainPath string) *Address { now := time.Now().Unix() index := GetMaxAddressIndex(coin, mpk.Id, chainPath) for { index += 1 address := ComputeAddress(coin, mpk.PubKey, mpk.Chain, chainPath, index) addr := &Address{address, coin, userId, wallet, mpk.Id, chainPath, index, now} addr, err := SaveAddress(addr) Info("[%v] Created new address: wallet:%v/%v mpkId:%v chainPath:%v/%v", coin, userId, wallet, mpk.Id, chainPath, index) switch db.GetErrorType(err) { case db.ERR_DUPLICATE_ENTRY: continue case nil: return addr default: panic(err) } } }
func Set(key, value string) { _, err := db.Exec( `INSERT INTO kvstore (key_, value) VALUES (?, ?)`, key, value, ) switch db.GetErrorType(err) { case nil: return case db.ERR_DUPLICATE_ENTRY: // Update instead _, err := db.Exec( `UPDATE kvstore SET value=? WHERE key=?`, value, key, ) if err != nil { panic(err) } return default: panic(err) } }
// Create a new user. func SaveUser(user *User) (*User, error) { // Create email confirmation code. if user.EmailCode == "" { user.EmailCode = RandId(24) } // Create TOTPKey. if len(user.TOTPKey) == 0 { user.TOTPKey = RandBytes(10) } // Scrypt the password. if user.Password != "" { salt := RandId(12) scryptPass, err := scrypt.Key([]byte(user.Password), []byte(salt), 16384, 8, 1, 32) if err != nil { return nil, err } user.Salt = []byte(salt) user.Scrypt = scryptPass } err := db.DoBeginSerializable(func(tx *db.ModelTx) { // Insert into users table. err := tx.QueryRow( `INSERT INTO auth_user (`+UserModel.FieldsInsert+`) VALUES (`+UserModel.Placeholders+`) RETURNING id`, user, ).Scan(&user.Id) if err != nil { panic(err) } // Set the chain_idx if user.Id > math.MaxInt32 { panic("User autoinc id has exceeded MaxInt32") } user.ChainIdx = int32(user.Id) _, err = tx.Exec( `UPDATE auth_user SET chain_idx = id WHERE id=?`, user.Id, ) if err != nil { panic(err) } // Generate an API key for the user apiKey := &APIKey{Key: RandId(24), UserId: user.Id} SaveAPIKey(tx, apiKey) }) switch db.GetErrorType(err) { case db.ERR_DUPLICATE_ENTRY: return nil, ERR_DUPLICATE_ADDRESS case nil: break default: panic(err) } return user, nil }