You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1186 lines
35 KiB

Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
  1. package historydb
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "time"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. "github.com/hermeznetwork/hermez-node/common"
  10. "github.com/hermeznetwork/hermez-node/db"
  11. "github.com/hermeznetwork/tracerr"
  12. "github.com/iden3/go-iden3-crypto/babyjub"
  13. "github.com/jmoiron/sqlx"
  14. "github.com/russross/meddler"
  15. )
  16. // GetLastBlockAPI retrieve the block with the highest block number from the DB
  17. func (hdb *HistoryDB) GetLastBlockAPI() (*common.Block, error) {
  18. cancel, err := hdb.apiConnCon.Acquire()
  19. defer cancel()
  20. if err != nil {
  21. return nil, tracerr.Wrap(err)
  22. }
  23. defer hdb.apiConnCon.Release()
  24. return hdb.GetLastBlock()
  25. }
  26. // GetBatchAPI return the batch with the given batchNum
  27. func (hdb *HistoryDB) GetBatchAPI(batchNum common.BatchNum) (*BatchAPI, error) {
  28. cancel, err := hdb.apiConnCon.Acquire()
  29. defer cancel()
  30. if err != nil {
  31. return nil, tracerr.Wrap(err)
  32. }
  33. defer hdb.apiConnCon.Release()
  34. return hdb.getBatchAPI(hdb.dbRead, batchNum)
  35. }
  36. // GetBatchInternalAPI return the batch with the given batchNum
  37. func (hdb *HistoryDB) GetBatchInternalAPI(batchNum common.BatchNum) (*BatchAPI, error) {
  38. return hdb.getBatchAPI(hdb.dbRead, batchNum)
  39. }
  40. func (hdb *HistoryDB) getBatchAPI(d meddler.DB, batchNum common.BatchNum) (*BatchAPI, error) {
  41. batch := &BatchAPI{}
  42. return batch, tracerr.Wrap(meddler.QueryRow(
  43. d, batch,
  44. `SELECT batch.item_id, batch.batch_num, batch.eth_block_num,
  45. batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root,
  46. batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num,
  47. block.timestamp, block.hash,
  48. COALESCE ((SELECT COUNT(*) FROM tx WHERE batch_num = batch.batch_num), 0) AS forged_txs
  49. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num
  50. WHERE batch_num = $1;`, batchNum,
  51. ))
  52. }
  53. // GetBatchesAPI return the batches applying the given filters
  54. func (hdb *HistoryDB) GetBatchesAPI(
  55. minBatchNum, maxBatchNum, slotNum *uint,
  56. forgerAddr *ethCommon.Address,
  57. fromItem, limit *uint, order string,
  58. ) ([]BatchAPI, uint64, error) {
  59. cancel, err := hdb.apiConnCon.Acquire()
  60. defer cancel()
  61. if err != nil {
  62. return nil, 0, tracerr.Wrap(err)
  63. }
  64. defer hdb.apiConnCon.Release()
  65. var query string
  66. var args []interface{}
  67. queryStr := `SELECT batch.item_id, batch.batch_num, batch.eth_block_num,
  68. batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root,
  69. batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num,
  70. block.timestamp, block.hash,
  71. COALESCE ((SELECT COUNT(*) FROM tx WHERE batch_num = batch.batch_num), 0) AS forged_txs,
  72. count(*) OVER() AS total_items
  73. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num `
  74. // Apply filters
  75. nextIsAnd := false
  76. // minBatchNum filter
  77. if minBatchNum != nil {
  78. if nextIsAnd {
  79. queryStr += "AND "
  80. } else {
  81. queryStr += "WHERE "
  82. }
  83. queryStr += "batch.batch_num > ? "
  84. args = append(args, minBatchNum)
  85. nextIsAnd = true
  86. }
  87. // maxBatchNum filter
  88. if maxBatchNum != nil {
  89. if nextIsAnd {
  90. queryStr += "AND "
  91. } else {
  92. queryStr += "WHERE "
  93. }
  94. queryStr += "batch.batch_num < ? "
  95. args = append(args, maxBatchNum)
  96. nextIsAnd = true
  97. }
  98. // slotNum filter
  99. if slotNum != nil {
  100. if nextIsAnd {
  101. queryStr += "AND "
  102. } else {
  103. queryStr += "WHERE "
  104. }
  105. queryStr += "batch.slot_num = ? "
  106. args = append(args, slotNum)
  107. nextIsAnd = true
  108. }
  109. // forgerAddr filter
  110. if forgerAddr != nil {
  111. if nextIsAnd {
  112. queryStr += "AND "
  113. } else {
  114. queryStr += "WHERE "
  115. }
  116. queryStr += "batch.forger_addr = ? "
  117. args = append(args, forgerAddr)
  118. nextIsAnd = true
  119. }
  120. // pagination
  121. if fromItem != nil {
  122. if nextIsAnd {
  123. queryStr += "AND "
  124. } else {
  125. queryStr += "WHERE "
  126. }
  127. if order == OrderAsc {
  128. queryStr += "batch.item_id >= ? "
  129. } else {
  130. queryStr += "batch.item_id <= ? "
  131. }
  132. args = append(args, fromItem)
  133. }
  134. queryStr += "ORDER BY batch.item_id "
  135. if order == OrderAsc {
  136. queryStr += " ASC "
  137. } else {
  138. queryStr += " DESC "
  139. }
  140. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  141. query = hdb.dbRead.Rebind(queryStr)
  142. // log.Debug(query)
  143. batchPtrs := []*BatchAPI{}
  144. if err := meddler.QueryAll(hdb.dbRead, &batchPtrs, query, args...); err != nil {
  145. return nil, 0, tracerr.Wrap(err)
  146. }
  147. batches := db.SlicePtrsToSlice(batchPtrs).([]BatchAPI)
  148. if len(batches) == 0 {
  149. return batches, 0, nil
  150. }
  151. return batches, batches[0].TotalItems - uint64(len(batches)), nil
  152. }
  153. // GetBestBidAPI returns the best bid in specific slot by slotNum
  154. func (hdb *HistoryDB) GetBestBidAPI(slotNum *int64) (BidAPI, error) {
  155. bid := &BidAPI{}
  156. cancel, err := hdb.apiConnCon.Acquire()
  157. defer cancel()
  158. if err != nil {
  159. return *bid, tracerr.Wrap(err)
  160. }
  161. defer hdb.apiConnCon.Release()
  162. err = meddler.QueryRow(
  163. hdb.dbRead, bid, `SELECT bid.*, block.timestamp, coordinator.forger_addr, coordinator.url
  164. FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
  165. INNER JOIN (
  166. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  167. GROUP BY bidder_addr
  168. ) c ON bid.bidder_addr = c.bidder_addr
  169. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  170. WHERE slot_num = $1 ORDER BY item_id DESC LIMIT 1;`, slotNum,
  171. )
  172. return *bid, tracerr.Wrap(err)
  173. }
  174. // GetBestBidsAPI returns the best bid in specific slot by slotNum
  175. func (hdb *HistoryDB) GetBestBidsAPI(
  176. minSlotNum, maxSlotNum *int64,
  177. bidderAddr *ethCommon.Address,
  178. limit *uint, order string,
  179. ) ([]BidAPI, uint64, error) {
  180. cancel, err := hdb.apiConnCon.Acquire()
  181. defer cancel()
  182. if err != nil {
  183. return nil, 0, tracerr.Wrap(err)
  184. }
  185. defer hdb.apiConnCon.Release()
  186. return hdb.getBestBidsAPI(hdb.dbRead, minSlotNum, maxSlotNum, bidderAddr, limit, order)
  187. }
  188. func (hdb *HistoryDB) getBestBidsAPI(
  189. d meddler.DB,
  190. minSlotNum, maxSlotNum *int64,
  191. bidderAddr *ethCommon.Address,
  192. limit *uint, order string,
  193. ) ([]BidAPI, uint64, error) {
  194. var query string
  195. var args []interface{}
  196. // JOIN the best bid of each slot with the latest update of each coordinator
  197. queryStr := `SELECT b.*, block.timestamp, coordinator.forger_addr, coordinator.url,
  198. COUNT(*) OVER() AS total_items FROM (
  199. SELECT slot_num, MAX(item_id) as maxitem
  200. FROM bid GROUP BY slot_num
  201. )
  202. AS x INNER JOIN bid AS b ON b.item_id = x.maxitem
  203. INNER JOIN block ON b.eth_block_num = block.eth_block_num
  204. INNER JOIN (
  205. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  206. GROUP BY bidder_addr
  207. ) c ON b.bidder_addr = c.bidder_addr
  208. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  209. WHERE (b.slot_num >= ? AND b.slot_num <= ?)`
  210. args = append(args, minSlotNum)
  211. args = append(args, maxSlotNum)
  212. // Apply filters
  213. if bidderAddr != nil {
  214. queryStr += " AND b.bidder_addr = ? "
  215. args = append(args, bidderAddr)
  216. }
  217. queryStr += " ORDER BY b.slot_num "
  218. if order == OrderAsc {
  219. queryStr += "ASC "
  220. } else {
  221. queryStr += "DESC "
  222. }
  223. if limit != nil {
  224. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  225. }
  226. query = hdb.dbRead.Rebind(queryStr)
  227. bidPtrs := []*BidAPI{}
  228. if err := meddler.QueryAll(d, &bidPtrs, query, args...); err != nil {
  229. return nil, 0, tracerr.Wrap(err)
  230. }
  231. // log.Debug(query)
  232. bids := db.SlicePtrsToSlice(bidPtrs).([]BidAPI)
  233. if len(bids) == 0 {
  234. return bids, 0, nil
  235. }
  236. return bids, bids[0].TotalItems - uint64(len(bids)), nil
  237. }
  238. // GetBidsAPI return the bids applying the given filters
  239. func (hdb *HistoryDB) GetBidsAPI(
  240. slotNum *int64, bidderAddr *ethCommon.Address,
  241. fromItem, limit *uint, order string,
  242. ) ([]BidAPI, uint64, error) {
  243. cancel, err := hdb.apiConnCon.Acquire()
  244. defer cancel()
  245. if err != nil {
  246. return nil, 0, tracerr.Wrap(err)
  247. }
  248. defer hdb.apiConnCon.Release()
  249. var query string
  250. var args []interface{}
  251. // JOIN each bid with the latest update of each coordinator
  252. queryStr := `SELECT bid.*, block.timestamp, coord.forger_addr, coord.url,
  253. COUNT(*) OVER() AS total_items
  254. FROM bid INNER JOIN block ON bid.eth_block_num = block.eth_block_num
  255. INNER JOIN (
  256. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  257. GROUP BY bidder_addr
  258. ) c ON bid.bidder_addr = c.bidder_addr
  259. INNER JOIN coordinator coord ON c.item_id = coord.item_id `
  260. // Apply filters
  261. nextIsAnd := false
  262. // slotNum filter
  263. if slotNum != nil {
  264. if nextIsAnd {
  265. queryStr += "AND "
  266. } else {
  267. queryStr += "WHERE "
  268. }
  269. queryStr += "bid.slot_num = ? "
  270. args = append(args, slotNum)
  271. nextIsAnd = true
  272. }
  273. // bidder filter
  274. if bidderAddr != nil {
  275. if nextIsAnd {
  276. queryStr += "AND "
  277. } else {
  278. queryStr += "WHERE "
  279. }
  280. queryStr += "bid.bidder_addr = ? "
  281. args = append(args, bidderAddr)
  282. nextIsAnd = true
  283. }
  284. if fromItem != nil {
  285. if nextIsAnd {
  286. queryStr += "AND "
  287. } else {
  288. queryStr += "WHERE "
  289. }
  290. if order == OrderAsc {
  291. queryStr += "bid.item_id >= ? "
  292. } else {
  293. queryStr += "bid.item_id <= ? "
  294. }
  295. args = append(args, fromItem)
  296. }
  297. // pagination
  298. queryStr += "ORDER BY bid.item_id "
  299. if order == OrderAsc {
  300. queryStr += "ASC "
  301. } else {
  302. queryStr += "DESC "
  303. }
  304. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  305. query, argsQ, err := sqlx.In(queryStr, args...)
  306. if err != nil {
  307. return nil, 0, tracerr.Wrap(err)
  308. }
  309. query = hdb.dbRead.Rebind(query)
  310. bids := []*BidAPI{}
  311. if err := meddler.QueryAll(hdb.dbRead, &bids, query, argsQ...); err != nil {
  312. return nil, 0, tracerr.Wrap(err)
  313. }
  314. if len(bids) == 0 {
  315. return []BidAPI{}, 0, nil
  316. }
  317. return db.SlicePtrsToSlice(bids).([]BidAPI), bids[0].TotalItems - uint64(len(bids)), nil
  318. }
  319. // GetTokenAPI returns a token from the DB given a TokenID
  320. func (hdb *HistoryDB) GetTokenAPI(tokenID common.TokenID) (*TokenWithUSD, error) {
  321. cancel, err := hdb.apiConnCon.Acquire()
  322. defer cancel()
  323. if err != nil {
  324. return nil, tracerr.Wrap(err)
  325. }
  326. defer hdb.apiConnCon.Release()
  327. return hdb.GetToken(tokenID)
  328. }
  329. // GetTokensAPI returns a list of tokens from the DB
  330. func (hdb *HistoryDB) GetTokensAPI(
  331. ids []common.TokenID, symbols []string, name string, fromItem,
  332. limit *uint, order string,
  333. ) ([]TokenWithUSD, uint64, error) {
  334. cancel, err := hdb.apiConnCon.Acquire()
  335. defer cancel()
  336. if err != nil {
  337. return nil, 0, tracerr.Wrap(err)
  338. }
  339. defer hdb.apiConnCon.Release()
  340. var query string
  341. var args []interface{}
  342. queryStr := `SELECT * , COUNT(*) OVER() AS total_items FROM token `
  343. // Apply filters
  344. nextIsAnd := false
  345. if len(ids) > 0 {
  346. queryStr += "WHERE token_id IN (?) "
  347. nextIsAnd = true
  348. args = append(args, ids)
  349. }
  350. if len(symbols) > 0 {
  351. if nextIsAnd {
  352. queryStr += "AND "
  353. } else {
  354. queryStr += "WHERE "
  355. }
  356. queryStr += "symbol IN (?) "
  357. args = append(args, symbols)
  358. nextIsAnd = true
  359. }
  360. if name != "" {
  361. if nextIsAnd {
  362. queryStr += "AND "
  363. } else {
  364. queryStr += "WHERE "
  365. }
  366. queryStr += "name ~ ? "
  367. args = append(args, name)
  368. nextIsAnd = true
  369. }
  370. if fromItem != nil {
  371. if nextIsAnd {
  372. queryStr += "AND "
  373. } else {
  374. queryStr += "WHERE "
  375. }
  376. if order == OrderAsc {
  377. queryStr += "item_id >= ? "
  378. } else {
  379. queryStr += "item_id <= ? "
  380. }
  381. args = append(args, fromItem)
  382. }
  383. // pagination
  384. queryStr += "ORDER BY item_id "
  385. if order == OrderAsc {
  386. queryStr += "ASC "
  387. } else {
  388. queryStr += "DESC "
  389. }
  390. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  391. query, argsQ, err := sqlx.In(queryStr, args...)
  392. if err != nil {
  393. return nil, 0, tracerr.Wrap(err)
  394. }
  395. query = hdb.dbRead.Rebind(query)
  396. tokens := []*TokenWithUSD{}
  397. if err := meddler.QueryAll(hdb.dbRead, &tokens, query, argsQ...); err != nil {
  398. return nil, 0, tracerr.Wrap(err)
  399. }
  400. if len(tokens) == 0 {
  401. return []TokenWithUSD{}, 0, nil
  402. }
  403. return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), uint64(len(tokens)) - tokens[0].TotalItems, nil
  404. }
  405. // GetTxAPI returns a tx from the DB given a TxID
  406. func (hdb *HistoryDB) GetTxAPI(txID common.TxID) (*TxAPI, error) {
  407. // Warning: amount_success and deposit_amount_success have true as default for
  408. // performance reasons. The expected default value is false (when txs are unforged)
  409. // this case is handled at the function func (tx TxAPI) MarshalJSON() ([]byte, error)
  410. cancel, err := hdb.apiConnCon.Acquire()
  411. defer cancel()
  412. if err != nil {
  413. return nil, tracerr.Wrap(err)
  414. }
  415. defer hdb.apiConnCon.Release()
  416. tx := &TxAPI{}
  417. err = meddler.QueryRow(
  418. hdb.dbRead, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  419. hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
  420. hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
  421. tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
  422. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  423. tx.deposit_amount, tx.deposit_amount_usd, tx.deposit_amount_success, tx.fee, tx.fee_usd, tx.nonce,
  424. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  425. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  426. token.usd_update, block.timestamp
  427. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  428. INNER JOIN block ON tx.eth_block_num = block.eth_block_num
  429. WHERE tx.id = $1;`, txID,
  430. )
  431. return tx, tracerr.Wrap(err)
  432. }
  433. // GetTxsAPI returns a list of txs from the DB using the HistoryTx struct
  434. // and pagination info
  435. func (hdb *HistoryDB) GetTxsAPI(
  436. ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp,
  437. tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType,
  438. fromItem, limit *uint, order string,
  439. ) ([]TxAPI, uint64, error) {
  440. // Warning: amount_success and deposit_amount_success have true as default for
  441. // performance reasons. The expected default value is false (when txs are unforged)
  442. // this case is handled at the function func (tx TxAPI) MarshalJSON() ([]byte, error)
  443. cancel, err := hdb.apiConnCon.Acquire()
  444. defer cancel()
  445. if err != nil {
  446. return nil, 0, tracerr.Wrap(err)
  447. }
  448. defer hdb.apiConnCon.Release()
  449. if ethAddr != nil && bjj != nil {
  450. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  451. }
  452. var query string
  453. var args []interface{}
  454. queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
  455. hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
  456. hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
  457. tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
  458. tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
  459. tx.deposit_amount, tx.deposit_amount_usd, tx.deposit_amount_success, tx.fee, tx.fee_usd, tx.nonce,
  460. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  461. token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
  462. token.usd_update, block.timestamp, count(*) OVER() AS total_items
  463. FROM tx INNER JOIN token ON tx.token_id = token.token_id
  464. INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
  465. // Apply filters
  466. nextIsAnd := false
  467. // ethAddr filter
  468. if ethAddr != nil {
  469. queryStr += "WHERE (tx.from_eth_addr = ? OR tx.to_eth_addr = ?) "
  470. nextIsAnd = true
  471. args = append(args, ethAddr, ethAddr)
  472. } else if bjj != nil { // bjj filter
  473. queryStr += "WHERE (tx.from_bjj = ? OR tx.to_bjj = ?) "
  474. nextIsAnd = true
  475. args = append(args, bjj, bjj)
  476. }
  477. // tokenID filter
  478. if tokenID != nil {
  479. if nextIsAnd {
  480. queryStr += "AND "
  481. } else {
  482. queryStr += "WHERE "
  483. }
  484. queryStr += "tx.token_id = ? "
  485. args = append(args, tokenID)
  486. nextIsAnd = true
  487. }
  488. // idx filter
  489. if idx != nil {
  490. if nextIsAnd {
  491. queryStr += "AND "
  492. } else {
  493. queryStr += "WHERE "
  494. }
  495. queryStr += "(tx.effective_from_idx = ? OR tx.to_idx = ?) "
  496. args = append(args, idx, idx)
  497. nextIsAnd = true
  498. }
  499. // batchNum filter
  500. if batchNum != nil {
  501. if nextIsAnd {
  502. queryStr += "AND "
  503. } else {
  504. queryStr += "WHERE "
  505. }
  506. queryStr += "tx.batch_num = ? "
  507. args = append(args, batchNum)
  508. nextIsAnd = true
  509. }
  510. // txType filter
  511. if txType != nil {
  512. if nextIsAnd {
  513. queryStr += "AND "
  514. } else {
  515. queryStr += "WHERE "
  516. }
  517. queryStr += "tx.type = ? "
  518. args = append(args, txType)
  519. nextIsAnd = true
  520. }
  521. if fromItem != nil {
  522. if nextIsAnd {
  523. queryStr += "AND "
  524. } else {
  525. queryStr += "WHERE "
  526. }
  527. if order == OrderAsc {
  528. queryStr += "tx.item_id >= ? "
  529. } else {
  530. queryStr += "tx.item_id <= ? "
  531. }
  532. args = append(args, fromItem)
  533. nextIsAnd = true
  534. }
  535. if nextIsAnd {
  536. queryStr += "AND "
  537. } else {
  538. queryStr += "WHERE "
  539. }
  540. queryStr += "tx.batch_num IS NOT NULL "
  541. // pagination
  542. queryStr += "ORDER BY tx.item_id "
  543. if order == OrderAsc {
  544. queryStr += " ASC "
  545. } else {
  546. queryStr += " DESC "
  547. }
  548. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  549. query = hdb.dbRead.Rebind(queryStr)
  550. // log.Debug(query)
  551. txsPtrs := []*TxAPI{}
  552. if err := meddler.QueryAll(hdb.dbRead, &txsPtrs, query, args...); err != nil {
  553. return nil, 0, tracerr.Wrap(err)
  554. }
  555. txs := db.SlicePtrsToSlice(txsPtrs).([]TxAPI)
  556. if len(txs) == 0 {
  557. return txs, 0, nil
  558. }
  559. return txs, txs[0].TotalItems - uint64(len(txs)), nil
  560. }
  561. // GetExitAPI returns a exit from the DB
  562. func (hdb *HistoryDB) GetExitAPI(batchNum *uint, idx *common.Idx) (*ExitAPI, error) {
  563. cancel, err := hdb.apiConnCon.Acquire()
  564. defer cancel()
  565. if err != nil {
  566. return nil, tracerr.Wrap(err)
  567. }
  568. defer hdb.apiConnCon.Release()
  569. exit := &ExitAPI{}
  570. err = meddler.QueryRow(
  571. hdb.dbRead, exit, `SELECT exit_tree.item_id, exit_tree.batch_num,
  572. hez_idx(exit_tree.account_idx, token.symbol) AS account_idx,
  573. account.bjj, account.eth_addr,
  574. exit_tree.merkle_proof, exit_tree.balance, exit_tree.instant_withdrawn,
  575. exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
  576. token.token_id, token.item_id AS token_item_id,
  577. token.eth_block_num AS token_block, token.eth_addr AS token_eth_addr, token.name, token.symbol,
  578. token.decimals, token.usd, token.usd_update
  579. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  580. INNER JOIN token ON account.token_id = token.token_id
  581. WHERE exit_tree.batch_num = $1 AND exit_tree.account_idx = $2;`, batchNum, idx,
  582. )
  583. return exit, tracerr.Wrap(err)
  584. }
  585. // GetExitsAPI returns a list of exits from the DB and pagination info
  586. func (hdb *HistoryDB) GetExitsAPI(
  587. ethAddr *ethCommon.Address, bjj *babyjub.PublicKeyComp, tokenID *common.TokenID,
  588. idx *common.Idx, batchNum *uint, onlyPendingWithdraws *bool,
  589. fromItem, limit *uint, order string,
  590. ) ([]ExitAPI, uint64, error) {
  591. if ethAddr != nil && bjj != nil {
  592. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  593. }
  594. cancel, err := hdb.apiConnCon.Acquire()
  595. defer cancel()
  596. if err != nil {
  597. return nil, 0, tracerr.Wrap(err)
  598. }
  599. defer hdb.apiConnCon.Release()
  600. var query string
  601. var args []interface{}
  602. queryStr := `SELECT exit_tree.item_id, exit_tree.batch_num,
  603. hez_idx(exit_tree.account_idx, token.symbol) AS account_idx,
  604. account.bjj, account.eth_addr,
  605. exit_tree.merkle_proof, exit_tree.balance, exit_tree.instant_withdrawn,
  606. exit_tree.delayed_withdraw_request, exit_tree.delayed_withdrawn,
  607. token.token_id, token.item_id AS token_item_id,
  608. token.eth_block_num AS token_block, token.eth_addr AS token_eth_addr, token.name, token.symbol,
  609. token.decimals, token.usd, token.usd_update, COUNT(*) OVER() AS total_items
  610. FROM exit_tree INNER JOIN account ON exit_tree.account_idx = account.idx
  611. INNER JOIN token ON account.token_id = token.token_id `
  612. // Apply filters
  613. nextIsAnd := false
  614. // ethAddr filter
  615. if ethAddr != nil {
  616. queryStr += "WHERE account.eth_addr = ? "
  617. nextIsAnd = true
  618. args = append(args, ethAddr)
  619. } else if bjj != nil { // bjj filter
  620. queryStr += "WHERE account.bjj = ? "
  621. nextIsAnd = true
  622. args = append(args, bjj)
  623. }
  624. // tokenID filter
  625. if tokenID != nil {
  626. if nextIsAnd {
  627. queryStr += "AND "
  628. } else {
  629. queryStr += "WHERE "
  630. }
  631. queryStr += "account.token_id = ? "
  632. args = append(args, tokenID)
  633. nextIsAnd = true
  634. }
  635. // idx filter
  636. if idx != nil {
  637. if nextIsAnd {
  638. queryStr += "AND "
  639. } else {
  640. queryStr += "WHERE "
  641. }
  642. queryStr += "exit_tree.account_idx = ? "
  643. args = append(args, idx)
  644. nextIsAnd = true
  645. }
  646. // batchNum filter
  647. if batchNum != nil {
  648. if nextIsAnd {
  649. queryStr += "AND "
  650. } else {
  651. queryStr += "WHERE "
  652. }
  653. queryStr += "exit_tree.batch_num = ? "
  654. args = append(args, batchNum)
  655. nextIsAnd = true
  656. }
  657. // onlyPendingWithdraws
  658. if onlyPendingWithdraws != nil {
  659. if *onlyPendingWithdraws {
  660. if nextIsAnd {
  661. queryStr += "AND "
  662. } else {
  663. queryStr += "WHERE "
  664. }
  665. queryStr += "(exit_tree.instant_withdrawn IS NULL AND exit_tree.delayed_withdrawn IS NULL) "
  666. nextIsAnd = true
  667. }
  668. }
  669. if fromItem != nil {
  670. if nextIsAnd {
  671. queryStr += "AND "
  672. } else {
  673. queryStr += "WHERE "
  674. }
  675. if order == OrderAsc {
  676. queryStr += "exit_tree.item_id >= ? "
  677. } else {
  678. queryStr += "exit_tree.item_id <= ? "
  679. }
  680. args = append(args, fromItem)
  681. // nextIsAnd = true
  682. }
  683. // pagination
  684. queryStr += "ORDER BY exit_tree.item_id "
  685. if order == OrderAsc {
  686. queryStr += " ASC "
  687. } else {
  688. queryStr += " DESC "
  689. }
  690. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  691. query = hdb.dbRead.Rebind(queryStr)
  692. // log.Debug(query)
  693. exits := []*ExitAPI{}
  694. if err := meddler.QueryAll(hdb.dbRead, &exits, query, args...); err != nil {
  695. return nil, 0, tracerr.Wrap(err)
  696. }
  697. if len(exits) == 0 {
  698. return []ExitAPI{}, 0, nil
  699. }
  700. return db.SlicePtrsToSlice(exits).([]ExitAPI), exits[0].TotalItems - uint64(len(exits)), nil
  701. }
  702. // GetCoordinatorsAPI returns a list of coordinators from the DB and pagination info
  703. func (hdb *HistoryDB) GetCoordinatorsAPI(
  704. bidderAddr, forgerAddr *ethCommon.Address,
  705. fromItem, limit *uint, order string,
  706. ) ([]CoordinatorAPI, uint64, error) {
  707. cancel, err := hdb.apiConnCon.Acquire()
  708. defer cancel()
  709. if err != nil {
  710. return nil, 0, tracerr.Wrap(err)
  711. }
  712. defer hdb.apiConnCon.Release()
  713. var query string
  714. var args []interface{}
  715. queryStr := `SELECT coordinator.*, COUNT(*) OVER() AS total_items
  716. FROM coordinator INNER JOIN (
  717. SELECT MAX(item_id) AS item_id FROM coordinator
  718. GROUP BY bidder_addr
  719. ) c ON coordinator.item_id = c.item_id `
  720. // Apply filters
  721. nextIsAnd := false
  722. if bidderAddr != nil {
  723. queryStr += "WHERE bidder_addr = ? "
  724. nextIsAnd = true
  725. args = append(args, bidderAddr)
  726. }
  727. if forgerAddr != nil {
  728. if nextIsAnd {
  729. queryStr += "AND "
  730. } else {
  731. queryStr += "WHERE "
  732. }
  733. queryStr += "forger_addr = ? "
  734. nextIsAnd = true
  735. args = append(args, forgerAddr)
  736. }
  737. if fromItem != nil {
  738. if nextIsAnd {
  739. queryStr += "AND "
  740. } else {
  741. queryStr += "WHERE "
  742. }
  743. if order == OrderAsc {
  744. queryStr += "coordinator.item_id >= ? "
  745. } else {
  746. queryStr += "coordinator.item_id <= ? "
  747. }
  748. args = append(args, fromItem)
  749. }
  750. // pagination
  751. queryStr += "ORDER BY coordinator.item_id "
  752. if order == OrderAsc {
  753. queryStr += " ASC "
  754. } else {
  755. queryStr += " DESC "
  756. }
  757. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  758. query = hdb.dbRead.Rebind(queryStr)
  759. coordinators := []*CoordinatorAPI{}
  760. if err := meddler.QueryAll(hdb.dbRead, &coordinators, query, args...); err != nil {
  761. return nil, 0, tracerr.Wrap(err)
  762. }
  763. if len(coordinators) == 0 {
  764. return []CoordinatorAPI{}, 0, nil
  765. }
  766. return db.SlicePtrsToSlice(coordinators).([]CoordinatorAPI),
  767. coordinators[0].TotalItems - uint64(len(coordinators)), nil
  768. }
  769. // GetAuctionVarsAPI returns auction variables
  770. func (hdb *HistoryDB) GetAuctionVarsAPI() (*common.AuctionVariables, error) {
  771. cancel, err := hdb.apiConnCon.Acquire()
  772. defer cancel()
  773. if err != nil {
  774. return nil, tracerr.Wrap(err)
  775. }
  776. defer hdb.apiConnCon.Release()
  777. auctionVars := &common.AuctionVariables{}
  778. err = meddler.QueryRow(
  779. hdb.dbRead, auctionVars, `SELECT * FROM auction_vars;`,
  780. )
  781. return auctionVars, tracerr.Wrap(err)
  782. }
  783. // GetAccountAPI returns an account by its index
  784. func (hdb *HistoryDB) GetAccountAPI(idx common.Idx) (*AccountAPI, error) {
  785. cancel, err := hdb.apiConnCon.Acquire()
  786. defer cancel()
  787. if err != nil {
  788. return nil, tracerr.Wrap(err)
  789. }
  790. defer hdb.apiConnCon.Release()
  791. account := &AccountAPI{}
  792. err = meddler.QueryRow(hdb.dbRead, account, `SELECT account.item_id, hez_idx(account.idx,
  793. token.symbol) as idx, account.batch_num, account.bjj, account.eth_addr,
  794. token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  795. token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd,
  796. token.usd_update, account_update.nonce, account_update.balance
  797. FROM account inner JOIN (
  798. SELECT idx, nonce, balance
  799. FROM account_update
  800. WHERE idx = $1
  801. ORDER BY item_id DESC LIMIT 1
  802. ) AS account_update ON account_update.idx = account.idx
  803. INNER JOIN token ON account.token_id = token.token_id
  804. WHERE account.idx = $1;`, idx)
  805. if err != nil {
  806. return nil, tracerr.Wrap(err)
  807. }
  808. return account, nil
  809. }
  810. // GetAccountsAPI returns a list of accounts from the DB and pagination info
  811. func (hdb *HistoryDB) GetAccountsAPI(
  812. tokenIDs []common.TokenID, ethAddr *ethCommon.Address,
  813. bjj *babyjub.PublicKeyComp, fromItem, limit *uint, order string,
  814. ) ([]AccountAPI, uint64, error) {
  815. if ethAddr != nil && bjj != nil {
  816. return nil, 0, tracerr.Wrap(errors.New("ethAddr and bjj are incompatible"))
  817. }
  818. cancel, err := hdb.apiConnCon.Acquire()
  819. defer cancel()
  820. if err != nil {
  821. return nil, 0, tracerr.Wrap(err)
  822. }
  823. defer hdb.apiConnCon.Release()
  824. var query string
  825. var args []interface{}
  826. queryStr := `SELECT account.item_id, hez_idx(account.idx, token.symbol) as idx, account.batch_num,
  827. account.bjj, account.eth_addr, token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
  828. token.eth_addr as token_eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update,
  829. account_update.nonce, account_update.balance, COUNT(*) OVER() AS total_items
  830. FROM account inner JOIN (
  831. SELECT DISTINCT idx,
  832. first_value(nonce) over(partition by idx ORDER BY item_id DESC) as nonce,
  833. first_value(balance) over(partition by idx ORDER BY item_id DESC) as balance
  834. FROM account_update
  835. ) AS account_update ON account_update.idx = account.idx INNER JOIN token ON account.token_id = token.token_id `
  836. // Apply filters
  837. nextIsAnd := false
  838. // ethAddr filter
  839. if ethAddr != nil {
  840. queryStr += "WHERE account.eth_addr = ? "
  841. nextIsAnd = true
  842. args = append(args, ethAddr)
  843. } else if bjj != nil { // bjj filter
  844. queryStr += "WHERE account.bjj = ? "
  845. nextIsAnd = true
  846. args = append(args, bjj)
  847. }
  848. // tokenID filter
  849. if len(tokenIDs) > 0 {
  850. if nextIsAnd {
  851. queryStr += "AND "
  852. } else {
  853. queryStr += "WHERE "
  854. }
  855. queryStr += "account.token_id IN (?) "
  856. args = append(args, tokenIDs)
  857. nextIsAnd = true
  858. }
  859. if fromItem != nil {
  860. if nextIsAnd {
  861. queryStr += "AND "
  862. } else {
  863. queryStr += "WHERE "
  864. }
  865. if order == OrderAsc {
  866. queryStr += "account.item_id >= ? "
  867. } else {
  868. queryStr += "account.item_id <= ? "
  869. }
  870. args = append(args, fromItem)
  871. }
  872. // pagination
  873. queryStr += "ORDER BY account.item_id "
  874. if order == OrderAsc {
  875. queryStr += " ASC "
  876. } else {
  877. queryStr += " DESC "
  878. }
  879. queryStr += fmt.Sprintf("LIMIT %d;", *limit)
  880. query, argsQ, err := sqlx.In(queryStr, args...)
  881. if err != nil {
  882. return nil, 0, tracerr.Wrap(err)
  883. }
  884. query = hdb.dbRead.Rebind(query)
  885. accounts := []*AccountAPI{}
  886. if err := meddler.QueryAll(hdb.dbRead, &accounts, query, argsQ...); err != nil {
  887. return nil, 0, tracerr.Wrap(err)
  888. }
  889. if len(accounts) == 0 {
  890. return []AccountAPI{}, 0, nil
  891. }
  892. return db.SlicePtrsToSlice(accounts).([]AccountAPI),
  893. accounts[0].TotalItems - uint64(len(accounts)), nil
  894. }
  895. // GetCommonAccountAPI returns the account associated to an account idx
  896. func (hdb *HistoryDB) GetCommonAccountAPI(idx common.Idx) (*common.Account, error) {
  897. cancel, err := hdb.apiConnCon.Acquire()
  898. defer cancel()
  899. if err != nil {
  900. return nil, tracerr.Wrap(err)
  901. }
  902. defer hdb.apiConnCon.Release()
  903. account := &common.Account{}
  904. err = meddler.QueryRow(
  905. hdb.dbRead, account, `SELECT idx, token_id, batch_num, bjj, eth_addr
  906. FROM account WHERE idx = $1;`, idx,
  907. )
  908. return account, tracerr.Wrap(err)
  909. }
  910. // GetCoordinatorAPI returns a coordinator by its bidderAddr
  911. func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  912. cancel, err := hdb.apiConnCon.Acquire()
  913. defer cancel()
  914. if err != nil {
  915. return nil, tracerr.Wrap(err)
  916. }
  917. defer hdb.apiConnCon.Release()
  918. return hdb.getCoordinatorAPI(hdb.dbRead, bidderAddr)
  919. }
  920. func (hdb *HistoryDB) getCoordinatorAPI(d meddler.DB, bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  921. coordinator := &CoordinatorAPI{}
  922. err := meddler.QueryRow(
  923. d, coordinator,
  924. "SELECT * FROM coordinator WHERE bidder_addr = $1 ORDER BY item_id DESC LIMIT 1;",
  925. bidderAddr,
  926. )
  927. return coordinator, tracerr.Wrap(err)
  928. }
  929. // GetNodeInfoAPI retusnt he NodeInfo
  930. func (hdb *HistoryDB) GetNodeInfoAPI() (*NodeInfo, error) {
  931. cancel, err := hdb.apiConnCon.Acquire()
  932. defer cancel()
  933. if err != nil {
  934. return nil, tracerr.Wrap(err)
  935. }
  936. defer hdb.apiConnCon.Release()
  937. return hdb.GetNodeInfo()
  938. }
  939. // GetBucketUpdatesInternalAPI returns the latest bucket updates
  940. func (hdb *HistoryDB) GetBucketUpdatesInternalAPI() ([]BucketUpdateAPI, error) {
  941. var bucketUpdates []*BucketUpdateAPI
  942. err := meddler.QueryAll(
  943. hdb.dbRead, &bucketUpdates,
  944. `SELECT num_bucket, withdrawals FROM bucket_update
  945. WHERE item_id in(SELECT max(item_id) FROM bucket_update
  946. group by num_bucket)
  947. ORDER BY num_bucket ASC;`,
  948. )
  949. return db.SlicePtrsToSlice(bucketUpdates).([]BucketUpdateAPI), tracerr.Wrap(err)
  950. }
  951. // GetNextForgersInternalAPI returns next forgers
  952. func (hdb *HistoryDB) GetNextForgersInternalAPI(auctionVars *common.AuctionVariables,
  953. auctionConsts *common.AuctionConstants,
  954. lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForgerAPI, error) {
  955. secondsPerBlock := int64(15) //nolint:gomnd
  956. // currentSlot and lastClosedSlot included
  957. limit := uint(lastClosedSlot - currentSlot + 1)
  958. bids, _, err := hdb.getBestBidsAPI(hdb.dbRead, &currentSlot, &lastClosedSlot, nil, &limit, "ASC")
  959. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  960. return nil, tracerr.Wrap(err)
  961. }
  962. nextForgers := []NextForgerAPI{}
  963. // Get min bid info
  964. var minBidInfo []MinBidInfo
  965. if currentSlot >= auctionVars.DefaultSlotSetBidSlotNum {
  966. // All min bids can be calculated with the last update of AuctionVariables
  967. minBidInfo = []MinBidInfo{{
  968. DefaultSlotSetBid: auctionVars.DefaultSlotSetBid,
  969. DefaultSlotSetBidSlotNum: auctionVars.DefaultSlotSetBidSlotNum,
  970. }}
  971. } else {
  972. // Get all the relevant updates from the DB
  973. minBidInfo, err = hdb.getMinBidInfo(hdb.dbRead, currentSlot, lastClosedSlot)
  974. if err != nil {
  975. return nil, tracerr.Wrap(err)
  976. }
  977. }
  978. // Create nextForger for each slot
  979. for i := currentSlot; i <= lastClosedSlot; i++ {
  980. fromBlock := i*int64(auctionConsts.BlocksPerSlot) +
  981. auctionConsts.GenesisBlockNum
  982. toBlock := (i+1)*int64(auctionConsts.BlocksPerSlot) +
  983. auctionConsts.GenesisBlockNum - 1
  984. nextForger := NextForgerAPI{
  985. Period: Period{
  986. SlotNum: i,
  987. FromBlock: fromBlock,
  988. ToBlock: toBlock,
  989. FromTimestamp: lastBlock.Timestamp.Add(time.Second *
  990. time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))),
  991. ToTimestamp: lastBlock.Timestamp.Add(time.Second *
  992. time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))),
  993. },
  994. }
  995. foundForger := false
  996. // If there is a bid for a slot, get forger (coordinator)
  997. for j := range bids {
  998. slotNum := bids[j].SlotNum
  999. if slotNum == i {
  1000. // There's a bid for the slot
  1001. // Check if the bid is greater than the minimum required
  1002. for i := 0; i < len(minBidInfo); i++ {
  1003. // Find the most recent update
  1004. if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum {
  1005. // Get min bid
  1006. minBidSelector := slotNum % int64(len(auctionVars.DefaultSlotSetBid))
  1007. minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector]
  1008. // Check if the bid has beaten the minimum
  1009. bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10)
  1010. if !ok {
  1011. return nil, tracerr.New("Wrong bid value, error parsing it as big.Int")
  1012. }
  1013. if minBid.Cmp(bid) == 1 {
  1014. // Min bid is greater than bid, the slot will be forged by boot coordinator
  1015. break
  1016. }
  1017. foundForger = true
  1018. break
  1019. }
  1020. }
  1021. if !foundForger { // There is no bid or it's smaller than the minimum
  1022. break
  1023. }
  1024. coordinator, err := hdb.getCoordinatorAPI(hdb.dbRead, bids[j].Bidder)
  1025. if err != nil {
  1026. return nil, tracerr.Wrap(err)
  1027. }
  1028. nextForger.Coordinator = *coordinator
  1029. break
  1030. }
  1031. }
  1032. // If there is no bid, the coordinator that will forge is boot coordinator
  1033. if !foundForger {
  1034. nextForger.Coordinator = CoordinatorAPI{
  1035. Forger: auctionVars.BootCoordinator,
  1036. URL: auctionVars.BootCoordinatorURL,
  1037. }
  1038. }
  1039. nextForgers = append(nextForgers, nextForger)
  1040. }
  1041. return nextForgers, nil
  1042. }
  1043. // GetMetricsInternalAPI returns the MetricsAPI
  1044. func (hdb *HistoryDB) GetMetricsInternalAPI(lastBatchNum common.BatchNum) (*MetricsAPI, error) {
  1045. var metrics MetricsAPI
  1046. // Get the first and last batch of the last 24h and their timestamps
  1047. // if u.state.Network.LastBatch == nil {
  1048. // return &metrics, nil
  1049. // }
  1050. type period struct {
  1051. FromBatchNum common.BatchNum `meddler:"from_batch_num"`
  1052. FromTimestamp time.Time `meddler:"from_timestamp"`
  1053. ToBatchNum common.BatchNum `meddler:"-"`
  1054. ToTimestamp time.Time `meddler:"to_timestamp"`
  1055. }
  1056. p := &period{
  1057. ToBatchNum: lastBatchNum,
  1058. }
  1059. if err := meddler.QueryRow(
  1060. hdb.dbRead, p, `SELECT
  1061. COALESCE (MIN(batch.batch_num), 0) as from_batch_num,
  1062. COALESCE (MIN(block.timestamp), NOW()) AS from_timestamp,
  1063. COALESCE (MAX(block.timestamp), NOW()) AS to_timestamp
  1064. FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num
  1065. WHERE block.timestamp >= NOW() - INTERVAL '24 HOURS';`,
  1066. ); err != nil {
  1067. return nil, tracerr.Wrap(err)
  1068. }
  1069. // Get the amount of txs of that period
  1070. row := hdb.dbRead.QueryRow(
  1071. `SELECT COUNT(*) as total_txs FROM tx WHERE tx.batch_num between $1 AND $2;`,
  1072. p.FromBatchNum, p.ToBatchNum,
  1073. )
  1074. var nTxs int
  1075. if err := row.Scan(&nTxs); err != nil {
  1076. return nil, tracerr.Wrap(err)
  1077. }
  1078. // Set txs/s
  1079. seconds := p.ToTimestamp.Sub(p.FromTimestamp).Seconds()
  1080. if seconds == 0 { // Avoid dividing by 0
  1081. seconds++
  1082. }
  1083. metrics.TransactionsPerSecond = float64(nTxs) / seconds
  1084. // Set txs/batch
  1085. nBatches := p.ToBatchNum - p.FromBatchNum + 1
  1086. if nBatches == 0 { // Avoid dividing by 0
  1087. nBatches++
  1088. }
  1089. if (p.ToBatchNum - p.FromBatchNum) > 0 {
  1090. fmt.Printf("DBG ntxs: %v, nBatches: %v\n", nTxs, nBatches)
  1091. metrics.TransactionsPerBatch = float64(nTxs) /
  1092. float64(nBatches)
  1093. } else {
  1094. metrics.TransactionsPerBatch = 0
  1095. }
  1096. // Get total fee of that period
  1097. row = hdb.dbRead.QueryRow(
  1098. `SELECT COALESCE (SUM(total_fees_usd), 0) FROM batch WHERE batch_num between $1 AND $2;`,
  1099. p.FromBatchNum, p.ToBatchNum,
  1100. )
  1101. var totalFee float64
  1102. if err := row.Scan(&totalFee); err != nil {
  1103. return nil, tracerr.Wrap(err)
  1104. }
  1105. // Set batch frequency
  1106. metrics.BatchFrequency = seconds / float64(nBatches)
  1107. if nTxs > 0 {
  1108. metrics.AvgTransactionFee = totalFee / float64(nTxs)
  1109. } else {
  1110. metrics.AvgTransactionFee = 0
  1111. }
  1112. // Get and set amount of registered accounts
  1113. type registeredAccounts struct {
  1114. TotalIdx int64 `meddler:"total_idx"`
  1115. TotalBJJ int64 `meddler:"total_bjj"`
  1116. }
  1117. ra := &registeredAccounts{}
  1118. if err := meddler.QueryRow(
  1119. hdb.dbRead, ra,
  1120. `SELECT COUNT(*) AS total_bjj, COUNT(DISTINCT(bjj)) AS total_idx FROM account;`,
  1121. ); err != nil {
  1122. return nil, tracerr.Wrap(err)
  1123. }
  1124. metrics.TotalAccounts = ra.TotalIdx
  1125. metrics.TotalBJJs = ra.TotalBJJ
  1126. // Get and set estimated time to forge L1 tx
  1127. row = hdb.dbRead.QueryRow(
  1128. `SELECT COALESCE (AVG(EXTRACT(EPOCH FROM (forged.timestamp - added.timestamp))), 0) FROM tx
  1129. INNER JOIN block AS added ON tx.eth_block_num = added.eth_block_num
  1130. INNER JOIN batch AS forged_batch ON tx.batch_num = forged_batch.batch_num
  1131. INNER JOIN block AS forged ON forged_batch.eth_block_num = forged.eth_block_num
  1132. WHERE tx.batch_num between $1 and $2 AND tx.is_l1 AND tx.user_origin;`,
  1133. p.FromBatchNum, p.ToBatchNum,
  1134. )
  1135. var timeToForgeL1 float64
  1136. if err := row.Scan(&timeToForgeL1); err != nil {
  1137. return nil, tracerr.Wrap(err)
  1138. }
  1139. metrics.EstimatedTimeToForgeL1 = timeToForgeL1
  1140. return &metrics, nil
  1141. }
  1142. // GetStateAPI returns the StateAPI
  1143. func (hdb *HistoryDB) GetStateAPI() (*StateAPI, error) {
  1144. cancel, err := hdb.apiConnCon.Acquire()
  1145. defer cancel()
  1146. if err != nil {
  1147. return nil, tracerr.Wrap(err)
  1148. }
  1149. defer hdb.apiConnCon.Release()
  1150. return hdb.getStateAPI(hdb.dbRead)
  1151. }