Rewind to checkpoint
This commit is contained in:
parent
130e0b9642
commit
63f04f8cf3
|
@ -140,3 +140,12 @@ table AddressBalance {
|
|||
table AddressBalanceVec {
|
||||
values:[AddressBalance];
|
||||
}
|
||||
|
||||
table Checkpoint {
|
||||
height:uint32;
|
||||
timestamp:uint32;
|
||||
}
|
||||
|
||||
table CheckpointVec {
|
||||
values:[Checkpoint];
|
||||
}
|
||||
|
|
|
@ -364,6 +364,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"resumeScan": MessageLookupByLibrary.simpleMessage("Resume Scan"),
|
||||
"retrieveTransactionDetails": MessageLookupByLibrary.simpleMessage(
|
||||
"Retrieve Transaction Details"),
|
||||
"rewindToCheckpoint":
|
||||
MessageLookupByLibrary.simpleMessage("Rewind to Checkpoint"),
|
||||
"roundToMillis":
|
||||
MessageLookupByLibrary.simpleMessage("Round to millis"),
|
||||
"saveBackup": MessageLookupByLibrary.simpleMessage("Save Backup"),
|
||||
|
@ -376,6 +378,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"secretShare": MessageLookupByLibrary.simpleMessage("Secret Share"),
|
||||
"seed": MessageLookupByLibrary.simpleMessage("Seed"),
|
||||
"selectAccount": MessageLookupByLibrary.simpleMessage("Select Account"),
|
||||
"selectCheckpoint":
|
||||
MessageLookupByLibrary.simpleMessage("Select Checkpoint"),
|
||||
"selectNotesToExcludeFromPayments":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Select notes to EXCLUDE from payments"),
|
||||
|
|
|
@ -29,7 +29,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Copia de seguridad - ${name} - Requerida para restaurar";
|
||||
|
||||
static String m3(rewindHeight) =>
|
||||
"Block reorg detected. Rewind to ${rewindHeight}";
|
||||
"Se ha detectado una reorganización de la blockchain. Rebobinar hasta ${rewindHeight}";
|
||||
|
||||
static String m4(address, amount) =>
|
||||
"Desea firmar una transacción a ${address} por ${amount}";
|
||||
|
@ -370,6 +370,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"resumeScan": MessageLookupByLibrary.simpleMessage("Reanudar Escaneo"),
|
||||
"retrieveTransactionDetails": MessageLookupByLibrary.simpleMessage(
|
||||
"Obtener detalles de la transacción"),
|
||||
"rewindToCheckpoint": MessageLookupByLibrary.simpleMessage("Rebobinar"),
|
||||
"roundToMillis":
|
||||
MessageLookupByLibrary.simpleMessage("Redondear a milésimas"),
|
||||
"saveBackup":
|
||||
|
@ -384,6 +385,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"seed": MessageLookupByLibrary.simpleMessage("Semilla"),
|
||||
"selectAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Seleccionar cuenta"),
|
||||
"selectCheckpoint":
|
||||
MessageLookupByLibrary.simpleMessage("Seleccionar Fetcha/Altura"),
|
||||
"selectNotesToExcludeFromPayments":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Seleccionar Notas a EXCLUIR de los pagos"),
|
||||
|
|
|
@ -370,6 +370,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"resumeScan": MessageLookupByLibrary.simpleMessage("Continuer Sync"),
|
||||
"retrieveTransactionDetails": MessageLookupByLibrary.simpleMessage(
|
||||
"Récupérer les détails de la transaction"),
|
||||
"rewindToCheckpoint":
|
||||
MessageLookupByLibrary.simpleMessage("Revenir au Bloc"),
|
||||
"roundToMillis":
|
||||
MessageLookupByLibrary.simpleMessage("Arrondir au millième"),
|
||||
"saveBackup":
|
||||
|
@ -384,6 +386,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"seed": MessageLookupByLibrary.simpleMessage("Graine"),
|
||||
"selectAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Choisissez un compte"),
|
||||
"selectCheckpoint": MessageLookupByLibrary.simpleMessage(
|
||||
"Selectionner la date du bloc"),
|
||||
"selectNotesToExcludeFromPayments":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Sélectionnez les billets à EXCLURE des paiements"),
|
||||
|
|
|
@ -2881,6 +2881,26 @@ class S {
|
|||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Rewind to Checkpoint`
|
||||
String get rewindToCheckpoint {
|
||||
return Intl.message(
|
||||
'Rewind to Checkpoint',
|
||||
name: 'rewindToCheckpoint',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Select Checkpoint`
|
||||
String get selectCheckpoint {
|
||||
return Intl.message(
|
||||
'Select Checkpoint',
|
||||
name: 'selectCheckpoint',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'account.dart';
|
|||
import 'animated_qr.dart';
|
||||
import 'budget.dart';
|
||||
import 'contact.dart';
|
||||
import 'db.dart';
|
||||
import 'history.dart';
|
||||
import 'generated/l10n.dart';
|
||||
import 'main.dart';
|
||||
|
@ -189,6 +190,7 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
|
|||
PopupMenuButton(
|
||||
child: Text(s.advanced),
|
||||
itemBuilder: (_) => [
|
||||
PopupMenuItem(child: Text(s.rewindToCheckpoint), value: "Rewind"),
|
||||
PopupMenuItem(child: Text(s.convertToWatchonly), enabled: active.canPay, value: "Cold"),
|
||||
PopupMenuItem(child: Text(s.signOffline), enabled: active.canPay, value: "Sign"),
|
||||
PopupMenuItem(child: Text(s.broadcast), value: "Broadcast"),
|
||||
|
@ -266,6 +268,9 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
|
|||
case "Pools":
|
||||
Navigator.of(context).pushNamed('/pools');
|
||||
break;
|
||||
case "Rewind":
|
||||
_rewind();
|
||||
break;
|
||||
case "Cold":
|
||||
_cold();
|
||||
break;
|
||||
|
@ -313,6 +318,33 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
|
|||
}
|
||||
}
|
||||
|
||||
_rewind() async {
|
||||
final s = S.of(context);
|
||||
int? height = null;
|
||||
final checkpoints = WarpApi.getCheckpoints(active.coin);
|
||||
final items = checkpoints.map((c) => DropdownMenuItem<int>(value: c.height,
|
||||
child: Text('${noteDateFormat.format(DateTime.fromMillisecondsSinceEpoch(c.timestamp * 1000))} - ${c.height}')
|
||||
)).toList();
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(s.rewindToCheckpoint),
|
||||
content: SingleChildScrollView(child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
DropdownButtonFormField<int>(items: items, hint: Text(s.selectCheckpoint), onChanged: (v) { height = v; })]
|
||||
)),
|
||||
actions: confirmButtons(context, () => Navigator.of(context).pop(true))
|
||||
)
|
||||
) ?? false;
|
||||
final h = height;
|
||||
if (confirmed && h != null) {
|
||||
showSnackBar(s.blockReorgDetectedRewind(h));
|
||||
WarpApi.rewindTo(h);
|
||||
}
|
||||
}
|
||||
|
||||
_cold() {
|
||||
showDialog(
|
||||
context: context,
|
||||
|
|
|
@ -281,5 +281,7 @@
|
|||
"newTemplate": "New Template",
|
||||
"name": "Name",
|
||||
"deleteTemplate": "Delete Template?",
|
||||
"areYouSureYouWantToDeleteThisSendTemplate": "Are you sure you want to delete this send template?"
|
||||
"areYouSureYouWantToDeleteThisSendTemplate": "Are you sure you want to delete this send template?",
|
||||
"rewindToCheckpoint": "Rewind to Checkpoint",
|
||||
"selectCheckpoint": "Select Checkpoint"
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@
|
|||
"newLabel": "Nueva",
|
||||
"invalidQrCode": "QR inválido: {message}",
|
||||
"expert": "Expert",
|
||||
"blockReorgDetectedRewind": "Block reorg detected. Rewind to {rewindHeight}",
|
||||
"blockReorgDetectedRewind": "Se ha detectado una reorganización de la blockchain. Rebobinar hasta {rewindHeight}",
|
||||
"goToTransaction": "Ver Transacción",
|
||||
"transactions": "Transacciónes",
|
||||
"synchronizationInProgress": "Sincronización en progreso",
|
||||
|
@ -279,5 +279,7 @@
|
|||
"newTemplate": "Nueva plantilla",
|
||||
"name": "Nombre",
|
||||
"deleteTemplate": "Eliminar plantilla?",
|
||||
"areYouSureYouWantToDeleteThisSendTemplate": "¿Está seguro de que desea eliminar esta plantilla de envío?"
|
||||
"areYouSureYouWantToDeleteThisSendTemplate": "¿Está seguro de que desea eliminar esta plantilla de envío?",
|
||||
"rewindToCheckpoint": "Rebobinar",
|
||||
"selectCheckpoint": "Seleccionar Fetcha/Altura"
|
||||
}
|
||||
|
|
|
@ -279,5 +279,7 @@
|
|||
"newTemplate": "Nouveau modèle",
|
||||
"name": "Nom",
|
||||
"deleteTemplate": "Effacer ce modèle?",
|
||||
"areYouSureYouWantToDeleteThisSendTemplate": "Voulez-vous vraiment supprimer ce modèle?"
|
||||
"areYouSureYouWantToDeleteThisSendTemplate": "Voulez-vous vraiment supprimer ce modèle?",
|
||||
"rewindToCheckpoint": "Revenir au Bloc",
|
||||
"selectCheckpoint": "Selectionner la date du bloc"
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit b9726bf29323140f07732ea664fdc1f3447048d7
|
||||
Subproject commit 337fe20b4fe7ec3b839c9d48e0a5308453e3419d
|
|
@ -3014,3 +3014,216 @@ class AddressBalanceVecObjectBuilder extends fb.ObjectBuilder {
|
|||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class Checkpoint {
|
||||
Checkpoint._(this._bc, this._bcOffset);
|
||||
factory Checkpoint(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<Checkpoint> reader = _CheckpointReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
int get height => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 4, 0);
|
||||
int get timestamp => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 6, 0);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Checkpoint{height: ${height}, timestamp: ${timestamp}}';
|
||||
}
|
||||
|
||||
CheckpointT unpack() => CheckpointT(
|
||||
height: height,
|
||||
timestamp: timestamp);
|
||||
|
||||
static int pack(fb.Builder fbBuilder, CheckpointT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class CheckpointT implements fb.Packable {
|
||||
int height;
|
||||
int timestamp;
|
||||
|
||||
CheckpointT({
|
||||
this.height = 0,
|
||||
this.timestamp = 0});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(2);
|
||||
fbBuilder.addUint32(0, height);
|
||||
fbBuilder.addUint32(1, timestamp);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CheckpointT{height: ${height}, timestamp: ${timestamp}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _CheckpointReader extends fb.TableReader<Checkpoint> {
|
||||
const _CheckpointReader();
|
||||
|
||||
@override
|
||||
Checkpoint createObject(fb.BufferContext bc, int offset) =>
|
||||
Checkpoint._(bc, offset);
|
||||
}
|
||||
|
||||
class CheckpointBuilder {
|
||||
CheckpointBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(2);
|
||||
}
|
||||
|
||||
int addHeight(int? height) {
|
||||
fbBuilder.addUint32(0, height);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
int addTimestamp(int? timestamp) {
|
||||
fbBuilder.addUint32(1, timestamp);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class CheckpointObjectBuilder extends fb.ObjectBuilder {
|
||||
final int? _height;
|
||||
final int? _timestamp;
|
||||
|
||||
CheckpointObjectBuilder({
|
||||
int? height,
|
||||
int? timestamp,
|
||||
})
|
||||
: _height = height,
|
||||
_timestamp = timestamp;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
fbBuilder.startTable(2);
|
||||
fbBuilder.addUint32(0, _height);
|
||||
fbBuilder.addUint32(1, _timestamp);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
class CheckpointVec {
|
||||
CheckpointVec._(this._bc, this._bcOffset);
|
||||
factory CheckpointVec(List<int> bytes) {
|
||||
final rootRef = fb.BufferContext.fromBytes(bytes);
|
||||
return reader.read(rootRef, 0);
|
||||
}
|
||||
|
||||
static const fb.Reader<CheckpointVec> reader = _CheckpointVecReader();
|
||||
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
List<Checkpoint>? get values => const fb.ListReader<Checkpoint>(Checkpoint.reader).vTableGetNullable(_bc, _bcOffset, 4);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CheckpointVec{values: ${values}}';
|
||||
}
|
||||
|
||||
CheckpointVecT unpack() => CheckpointVecT(
|
||||
values: values?.map((e) => e.unpack()).toList());
|
||||
|
||||
static int pack(fb.Builder fbBuilder, CheckpointVecT? object) {
|
||||
if (object == null) return 0;
|
||||
return object.pack(fbBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
class CheckpointVecT implements fb.Packable {
|
||||
List<CheckpointT>? values;
|
||||
|
||||
CheckpointVecT({
|
||||
this.values});
|
||||
|
||||
@override
|
||||
int pack(fb.Builder fbBuilder) {
|
||||
final int? valuesOffset = values == null ? null
|
||||
: fbBuilder.writeList(values!.map((b) => b.pack(fbBuilder)).toList());
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, valuesOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CheckpointVecT{values: ${values}}';
|
||||
}
|
||||
}
|
||||
|
||||
class _CheckpointVecReader extends fb.TableReader<CheckpointVec> {
|
||||
const _CheckpointVecReader();
|
||||
|
||||
@override
|
||||
CheckpointVec createObject(fb.BufferContext bc, int offset) =>
|
||||
CheckpointVec._(bc, offset);
|
||||
}
|
||||
|
||||
class CheckpointVecBuilder {
|
||||
CheckpointVecBuilder(this.fbBuilder);
|
||||
|
||||
final fb.Builder fbBuilder;
|
||||
|
||||
void begin() {
|
||||
fbBuilder.startTable(1);
|
||||
}
|
||||
|
||||
int addValuesOffset(int? offset) {
|
||||
fbBuilder.addOffset(0, offset);
|
||||
return fbBuilder.offset;
|
||||
}
|
||||
|
||||
int finish() {
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class CheckpointVecObjectBuilder extends fb.ObjectBuilder {
|
||||
final List<CheckpointObjectBuilder>? _values;
|
||||
|
||||
CheckpointVecObjectBuilder({
|
||||
List<CheckpointObjectBuilder>? values,
|
||||
})
|
||||
: _values = values;
|
||||
|
||||
/// Finish building, and store into the [fbBuilder].
|
||||
@override
|
||||
int finish(fb.Builder fbBuilder) {
|
||||
final int? valuesOffset = _values == null ? null
|
||||
: fbBuilder.writeList(_values!.map((b) => b.getOrCreateOffset(fbBuilder)).toList());
|
||||
fbBuilder.startTable(1);
|
||||
fbBuilder.addOffset(0, valuesOffset);
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
|
||||
/// Convenience method to serialize to byte list.
|
||||
@override
|
||||
Uint8List toBytes([String? fileIdentifier]) {
|
||||
final fbBuilder = fb.Builder(deduplicateTables: false);
|
||||
fbBuilder.finish(finish(fbBuilder), fileIdentifier);
|
||||
return fbBuilder.buffer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -543,6 +543,12 @@ class WarpApi {
|
|||
static void invertExcluded(int coin, int id) {
|
||||
unwrapResultU8(warp_api_lib.invert_excluded(coin, id));
|
||||
}
|
||||
|
||||
static List<Checkpoint> getCheckpoints(int coin) {
|
||||
final r = unwrapResultBytes(warp_api_lib.get_checkpoints(coin));
|
||||
final quotes = CheckpointVec(r);
|
||||
return quotes.values!;
|
||||
}
|
||||
}
|
||||
|
||||
String signOnlyIsolateFn(SignOnlyParams params) {
|
||||
|
|
|
@ -1215,6 +1215,19 @@ class NativeLibrary {
|
|||
late final _dart_invert_excluded _invert_excluded =
|
||||
_invert_excluded_ptr.asFunction<_dart_invert_excluded>();
|
||||
|
||||
CResult______u8 get_checkpoints(
|
||||
int coin,
|
||||
) {
|
||||
return _get_checkpoints(
|
||||
coin,
|
||||
);
|
||||
}
|
||||
|
||||
late final _get_checkpoints_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_get_checkpoints>>('get_checkpoints');
|
||||
late final _dart_get_checkpoints _get_checkpoints =
|
||||
_get_checkpoints_ptr.asFunction<_dart_get_checkpoints>();
|
||||
|
||||
int has_cuda() {
|
||||
return _has_cuda();
|
||||
}
|
||||
|
@ -2180,6 +2193,14 @@ typedef _dart_invert_excluded = CResult_u8 Function(
|
|||
int id,
|
||||
);
|
||||
|
||||
typedef _c_get_checkpoints = CResult______u8 Function(
|
||||
ffi.Uint8 coin,
|
||||
);
|
||||
|
||||
typedef _dart_get_checkpoints = CResult______u8 Function(
|
||||
int coin,
|
||||
);
|
||||
|
||||
typedef _c_has_cuda = ffi.Int8 Function();
|
||||
|
||||
typedef _dart_has_cuda = int Function();
|
||||
|
|
|
@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.2.17+345
|
||||
version: 1.2.17+346
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
|
Loading…
Reference in New Issue