Rewind to checkpoint

This commit is contained in:
Hanh 2023-01-08 00:54:55 +08:00
parent 130e0b9642
commit 63f04f8cf3
14 changed files with 325 additions and 7 deletions

View File

@ -140,3 +140,12 @@ table AddressBalance {
table AddressBalanceVec {
values:[AddressBalance];
}
table Checkpoint {
height:uint32;
timestamp:uint32;
}
table CheckpointVec {
values:[Checkpoint];
}

View File

@ -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"),

View File

@ -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"),

View File

@ -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"),

View File

@ -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> {

View File

@ -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;
@ -312,6 +317,33 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
Navigator.of(context).pushNamed('/keytool');
}
}
_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(

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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();

View File

@ -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"